Line data Source code
1 : #include "fd_tls.h"
2 : #include "fd_tls_proto.h"
3 : #include "fd_tls_serde.h"
4 : #include "../../ballet/x509/fd_x509.h"
5 :
6 : typedef struct fd_tls_u24 tls_u24; /* code generator helper */
7 :
8 : /* RFC 8446 Section 4.1.3: "the server's value [random] will be set to the
9 : SHA-256 hash of 'HelloRetryRequest'" */
10 : static uchar const hello_retry_magic[ 32 ] =
11 : { 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
12 : 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
13 : 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E,
14 : 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C };
15 :
16 : #define FD_TLS_ENCODE_EXT_BEGIN( type ) \
17 : do { \
18 : int valid = 1; \
19 : FD_TLS_SERDE_LOCATE( ext_type, _, ushort, 1 ); \
20 : FD_TLS_SERDE_LOCATE( ext_sz, _, ushort, 1 ); \
21 : FD_TLS_SERDE_CHECK \
22 : ushort * ext_type_ptr = (ushort *)_field_ext_type_laddr; \
23 : ushort * ext_sz_ptr = (ushort *)_field_ext_sz_laddr; \
24 : ulong const ext_start = wire_laddr; \
25 : *ext_type_ptr = fd_ushort_bswap( type );
26 :
27 : #define FD_TLS_ENCODE_EXT_END \
28 : ulong ext_sz = wire_laddr - ext_start; \
29 : if( FD_UNLIKELY( ext_sz > USHORT_MAX ) ) \
30 : return -(long)FD_TLS_ALERT_INTERNAL_ERROR; \
31 : *ext_sz_ptr = fd_ushort_bswap( ext_sz ); \
32 : } while(0)
33 :
34 : /* Decode ClientHello (RFC 8446 Section 4.1.2) */
35 : long
36 : fd_tls_decode_client_hello( fd_tls_client_hello_t * out,
37 : uchar const * const wire,
38 7209 : ulong wire_sz ) {
39 :
40 7209 : ulong wire_laddr = (ulong)wire;
41 :
42 : /* Decode static sized part of client hello.
43 : (Assuming that session ID field is of a certain size) */
44 :
45 7209 : ushort legacy_version; /* ==FD_TLS_VERSION_TLS12 */
46 7209 : uchar legacy_session_id_sz; /* ==0 */
47 :
48 7209 : # define FIELDS( FIELD ) \
49 14418 : FIELD( 0, &legacy_version, ushort, 1 ) \
50 14418 : FIELD( 1, &out->random[0], uchar, 32UL ) \
51 14418 : FIELD( 2, &legacy_session_id_sz, uchar, 1 )
52 14418 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
53 7209 : # undef FIELDS
54 :
55 7209 : if( FD_UNLIKELY( ( legacy_session_id_sz > 32 ) |
56 7209 : ( wire_sz < legacy_session_id_sz ) ) )
57 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
58 :
59 7209 : out->session_id.buf = (void *)wire_laddr;
60 7209 : out->session_id.bufsz = legacy_session_id_sz;
61 7209 : wire_laddr += legacy_session_id_sz;
62 7209 : wire_sz -= legacy_session_id_sz;
63 :
64 : /* Decode cipher suite list */
65 :
66 7209 : if( FD_UNLIKELY( wire_sz<2UL || !FD_LOAD( ushort, (void const *)wire_laddr ) ) )
67 3 : return -FD_TLS_ALERT_DECODE_ERROR;
68 28824 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(ushort) ) {
69 27831 : ushort cipher_suite;
70 27831 : FD_TLS_DECODE_FIELD( &cipher_suite, ushort );
71 :
72 27831 : switch( cipher_suite ) {
73 7179 : case FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256:
74 7179 : out->cipher_suites.aes_128_gcm_sha256 = 1;
75 7179 : break;
76 20652 : default:
77 : /* Ignore unsupported cipher suites ... */
78 20652 : break;
79 27831 : }
80 27831 : }
81 7206 : FD_TLS_DECODE_LIST_END
82 :
83 : /* Decode next static sized part of client hello */
84 :
85 7206 : uchar legacy_compression_method_cnt; /* == 1 */
86 7206 : uchar legacy_compression_methods[ 1 ]; /* =={0} */
87 :
88 7206 : # define FIELDS( FIELD ) \
89 14412 : FIELD( 5, &legacy_compression_method_cnt, uchar, 1 ) \
90 14412 : FIELD( 6, &legacy_compression_methods[0], uchar, 1 )
91 14412 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
92 7206 : # undef FIELDS
93 :
94 7206 : if( FD_UNLIKELY( ( legacy_compression_method_cnt != 1 )
95 7206 : | ( legacy_compression_methods[0] != 0 ) ) )
96 0 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
97 :
98 : /* Read extensions */
99 :
100 7206 : ulong seen = 0UL;
101 48648 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
102 : /* Read extension type and length */
103 48648 : ushort ext_type;
104 48648 : ushort ext_sz;
105 48648 : # define FIELDS( FIELD ) \
106 97296 : FIELD( 0, &ext_type, ushort, 1 ) \
107 97296 : FIELD( 1, &ext_sz, ushort, 1 )
108 97296 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
109 48648 : # undef FIELDS
110 :
111 : /* Bounds check extension data */
112 48648 : if( FD_UNLIKELY( ext_sz > wire_sz ) )
113 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
114 :
115 : /* RFC 8446 Section 4.2: at most one extension of each type */
116 48648 : if( ext_type<64 ) {
117 47721 : if( FD_UNLIKELY( seen & (1UL<<ext_type) ) ) return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
118 47709 : seen |= 1UL<<ext_type;
119 47709 : }
120 :
121 : /* Decode extension data */
122 48636 : uchar const * ext_data = (uchar const *)wire_laddr;
123 48636 : long ext_parse_res;
124 48636 : switch( ext_type ) {
125 7191 : case FD_TLS_EXT_SUPPORTED_VERSIONS:
126 7191 : ext_parse_res = fd_tls_decode_ext_supported_versions( &out->supported_versions, ext_data, ext_sz );
127 7191 : break;
128 879 : case FD_TLS_EXT_SERVER_NAME:
129 879 : ext_parse_res = fd_tls_decode_ext_server_name( &out->server_name, ext_data, ext_sz );
130 879 : break;
131 7203 : case FD_TLS_EXT_SUPPORTED_GROUPS:
132 7203 : ext_parse_res = fd_tls_decode_ext_supported_groups( &out->supported_groups, ext_data, ext_sz );
133 7203 : break;
134 7203 : case FD_TLS_EXT_SIGNATURE_ALGORITHMS:
135 7203 : ext_parse_res = fd_tls_decode_ext_signature_algorithms( &out->signature_algorithms, ext_data, ext_sz );
136 7203 : break;
137 213 : case FD_TLS_EXT_SIGNATURE_ALGORITHMS_CERT:
138 213 : ext_parse_res = fd_tls_decode_ext_signature_algorithms( &out->signature_algorithms_cert, ext_data, ext_sz );
139 213 : break;
140 7191 : case FD_TLS_EXT_KEY_SHARE:
141 7191 : ext_parse_res = fd_tls_decode_key_share_list( &out->key_share, ext_data, ext_sz );
142 7191 : break;
143 6084 : case FD_TLS_EXT_QUIC_TRANSPORT_PARAMS:
144 6084 : ext_parse_res = fd_tls_decode_ext_quic_tp( &out->quic_tp, ext_data, ext_sz );
145 6084 : break;
146 6477 : case FD_TLS_EXT_ALPN:
147 6477 : ext_parse_res = fd_tls_decode_ext_alpn( &out->alpn, ext_data, ext_sz );
148 6477 : break;
149 6195 : default:
150 6195 : ext_parse_res = (long)ext_sz;
151 6195 : break;
152 48636 : }
153 48636 : if( FD_UNLIKELY( ext_parse_res<0L ) )
154 0 : return ext_parse_res;
155 48636 : if( FD_UNLIKELY( ext_parse_res != (long)ext_sz ) )
156 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
157 :
158 : /* Seek to next extension */
159 48636 : wire_laddr += ext_sz;
160 48636 : wire_sz -= ext_sz;
161 48636 : }
162 7194 : FD_TLS_DECODE_LIST_END
163 :
164 7194 : return (long)( wire_laddr - (ulong)wire );
165 7206 : }
166 :
167 : long
168 : fd_tls_encode_client_hello( fd_tls_client_hello_t const * in,
169 : uchar * wire,
170 9747 : ulong wire_sz ) {
171 :
172 9747 : ulong wire_laddr = (ulong)wire;
173 :
174 : /* Encode static sized part of client hello */
175 :
176 9747 : ushort legacy_version = FD_TLS_VERSION_TLS12;
177 9747 : uchar legacy_session_id_sz = (uchar)in->session_id.bufsz;
178 9747 : ushort cipher_suite_sz = 1*sizeof(ushort);
179 9747 : ushort cipher_suites[1] = { FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256 };
180 9747 : uchar legacy_comp_method_sz = 1;
181 9747 : uchar legacy_comp_method[1] = {0};
182 :
183 9747 : # define FIELDS( FIELD ) \
184 19494 : FIELD( 0, &legacy_version, ushort, 1 ) \
185 19494 : FIELD( 1, in->random, uchar, 32UL ) \
186 19494 : FIELD( 2, &legacy_session_id_sz, uchar, 1 )
187 19494 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
188 9747 : # undef FIELDS
189 :
190 : /* Encode session_id (0 for QUIC, 32 random bytes for TCP middlebox compat) */
191 :
192 9747 : if( legacy_session_id_sz ) {
193 3627 : if( FD_UNLIKELY( legacy_session_id_sz > 32 ) )
194 0 : return -(long)FD_TLS_ALERT_INTERNAL_ERROR;
195 3627 : if( FD_UNLIKELY( (ulong)legacy_session_id_sz > wire_sz ) )
196 0 : return -(long)FD_TLS_ALERT_INTERNAL_ERROR;
197 3627 : fd_memcpy( (void *)wire_laddr, in->session_id.buf, legacy_session_id_sz );
198 3627 : wire_laddr += legacy_session_id_sz;
199 3627 : wire_sz -= legacy_session_id_sz;
200 3627 : }
201 :
202 9747 : # define FIELDS( FIELD ) \
203 19494 : FIELD( 0, &cipher_suite_sz, ushort, 1 ) \
204 19494 : FIELD( 1, cipher_suites, ushort, 1 ) \
205 19494 : FIELD( 2, &legacy_comp_method_sz, uchar, 1 ) \
206 19494 : FIELD( 3, legacy_comp_method, uchar, 1 )
207 19494 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
208 9747 : # undef FIELDS
209 :
210 : /* Encode extensions */
211 :
212 9747 : ushort * extension_tot_sz = FD_TLS_SKIP_FIELD( ushort );
213 9747 : ulong extension_start = wire_laddr;
214 :
215 9747 : ushort ext_supported_versions_ext_type = FD_TLS_EXT_SUPPORTED_VERSIONS;
216 9747 : ushort ext_supported_versions_ext_sz = 3;
217 9747 : uchar ext_supported_versions_sz = 2;
218 9747 : ushort ext_supported_versions[1] = { FD_TLS_VERSION_TLS13 };
219 :
220 9747 : ushort ext_key_share_ext_type = FD_TLS_EXT_KEY_SHARE;
221 9747 : ushort ext_key_share_ext_sz = 38;
222 9747 : ushort ext_key_share_sz1 = 36;
223 9747 : ushort ext_key_share_group = FD_TLS_GROUP_X25519;
224 9747 : ushort ext_key_share_sz = 32;
225 :
226 9747 : ushort ext_supported_groups_ext_type = FD_TLS_EXT_SUPPORTED_GROUPS;
227 9747 : ushort ext_supported_groups_ext_sz = 4;
228 9747 : ushort ext_supported_groups_sz = 2;
229 9747 : ushort ext_supported_groups[1] = { FD_TLS_GROUP_X25519 };
230 :
231 : /* Advertise the signature algorithms the caller opted into, in
232 : descending order of preference */
233 :
234 9747 : ushort ext_sigalg[5];
235 9747 : ulong ext_sigalg_cnt = 0UL;
236 9747 : if( in->signature_algorithms.ecdsa_secp256r1_sha256 )
237 3627 : ext_sigalg[ ext_sigalg_cnt++ ] = FD_TLS_SIGNATURE_ECDSA_SECP256R1_SHA256;
238 9747 : if( in->signature_algorithms.ed25519 )
239 9747 : ext_sigalg[ ext_sigalg_cnt++ ] = FD_TLS_SIGNATURE_ED25519;
240 9747 : if( in->signature_algorithms.rsa_pss_rsae_sha256 )
241 3627 : ext_sigalg[ ext_sigalg_cnt++ ] = FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA256;
242 9747 : if( in->signature_algorithms.rsa_pss_rsae_sha384 )
243 3627 : ext_sigalg[ ext_sigalg_cnt++ ] = FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA384;
244 9747 : if( in->signature_algorithms.rsa_pss_rsae_sha512 )
245 3627 : ext_sigalg[ ext_sigalg_cnt++ ] = FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA512;
246 9747 : if( FD_UNLIKELY( !ext_sigalg_cnt ) ) return -(long)FD_TLS_ALERT_INTERNAL_ERROR;
247 :
248 9747 : ushort ext_sigalg_ext_type = FD_TLS_EXT_SIGNATURE_ALGORITHMS;
249 9747 : ushort ext_sigalg_sz = (ushort)( 2UL*ext_sigalg_cnt );
250 9747 : ushort ext_sigalg_ext_sz = (ushort)( 2U+ext_sigalg_sz );
251 :
252 9747 : # define FIELDS( FIELD ) \
253 19494 : FIELD( 0, &ext_supported_versions_ext_type, ushort, 1 ) \
254 19494 : FIELD( 1, &ext_supported_versions_ext_sz, ushort, 1 ) \
255 19494 : FIELD( 2, &ext_supported_versions_sz, uchar, 1 ) \
256 19494 : FIELD( 3, ext_supported_versions, ushort, 1 ) \
257 19494 : FIELD( 4, &ext_key_share_ext_type, ushort, 1 ) \
258 19494 : FIELD( 5, &ext_key_share_ext_sz, ushort, 1 ) \
259 19494 : FIELD( 6, &ext_key_share_sz1, ushort, 1 ) \
260 19494 : FIELD( 7, &ext_key_share_group, ushort, 1 ) \
261 19494 : FIELD( 8, &ext_key_share_sz, ushort, 1 ) \
262 19494 : FIELD( 9, &in->key_share.x25519[0], uchar, 32UL ) \
263 19494 : FIELD(10, &ext_supported_groups_ext_type, ushort, 1 ) \
264 19494 : FIELD(11, &ext_supported_groups_ext_sz, ushort, 1 ) \
265 19494 : FIELD(12, &ext_supported_groups_sz, ushort, 1 ) \
266 19494 : FIELD(13, ext_supported_groups, ushort, 1 ) \
267 19494 : FIELD(14, &ext_sigalg_ext_type, ushort, 1 ) \
268 19494 : FIELD(15, &ext_sigalg_ext_sz, ushort, 1 ) \
269 19494 : FIELD(16, &ext_sigalg_sz, ushort, 1 ) \
270 19494 : FIELD(17, ext_sigalg, ushort, ext_sigalg_cnt )
271 19494 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
272 9747 : # undef FIELDS
273 :
274 9747 : do {
275 9747 : ushort schemes[6];
276 9747 : ulong cnt = 0UL;
277 9747 : if( in->signature_algorithms_cert.ecdsa_secp256r1_sha256 ) schemes[cnt++] = FD_TLS_SIGNATURE_ECDSA_SECP256R1_SHA256;
278 9747 : if( in->signature_algorithms_cert.ecdsa_secp384r1_sha384 ) schemes[cnt++] = FD_TLS_SIGNATURE_ECDSA_SECP384R1_SHA384;
279 9747 : if( in->signature_algorithms_cert.ed25519 ) schemes[cnt++] = FD_TLS_SIGNATURE_ED25519;
280 9747 : if( in->signature_algorithms_cert.rsa_pkcs1_sha256 ) schemes[cnt++] = FD_TLS_SIGNATURE_RSA_PKCS1_SHA256;
281 9747 : if( in->signature_algorithms_cert.rsa_pkcs1_sha384 ) schemes[cnt++] = FD_TLS_SIGNATURE_RSA_PKCS1_SHA384;
282 9747 : if( in->signature_algorithms_cert.rsa_pkcs1_sha512 ) schemes[cnt++] = FD_TLS_SIGNATURE_RSA_PKCS1_SHA512;
283 9747 : if( !cnt ) break;
284 3627 : ushort type = FD_TLS_EXT_SIGNATURE_ALGORITHMS_CERT;
285 3627 : ushort list_sz = (ushort)(2UL*cnt);
286 3627 : ushort ext_sz = (ushort)(list_sz+2U);
287 3627 : # define FIELDS( FIELD ) \
288 7254 : FIELD( 0, &type, ushort, 1 ) \
289 7254 : FIELD( 1, &ext_sz, ushort, 1 ) \
290 7254 : FIELD( 2, &list_sz, ushort, 1 ) \
291 7254 : FIELD( 3, schemes, ushort, cnt )
292 7254 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
293 3627 : # undef FIELDS
294 3627 : } while(0);
295 :
296 : /* Add Server Name Indication (SNI) */
297 :
298 9747 : if( in->server_name.host_name_len ) {
299 3192 : ushort sni_name_len = in->server_name.host_name_len;
300 3192 : ushort sni_list_len = (ushort)( 1 + 2 + sni_name_len ); /* name_type(1) + name_len(2) + name */
301 3192 : ushort sni_ext_type = FD_TLS_EXT_SERVER_NAME;
302 3192 : ushort sni_ext_sz = (ushort)( 2 + sni_list_len ); /* list_len(2) + list */
303 3192 : uchar sni_name_type = FD_TLS_SERVER_NAME_TYPE_DNS;
304 3192 : # define FIELDS( FIELD ) \
305 6384 : FIELD( 0, &sni_ext_type, ushort, 1 ) \
306 6384 : FIELD( 1, &sni_ext_sz, ushort, 1 ) \
307 6384 : FIELD( 2, &sni_list_len, ushort, 1 ) \
308 6384 : FIELD( 3, &sni_name_type, uchar, 1 ) \
309 6384 : FIELD( 4, &sni_name_len, ushort, 1 ) \
310 6384 : FIELD( 5, in->server_name.host_name, uchar, sni_name_len )
311 6384 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
312 3192 : # undef FIELDS
313 3192 : }
314 :
315 : /* Add ALPN */
316 :
317 9747 : if( in->alpn.bufsz ) {
318 7626 : fd_tls_ext_hdr_t ext_hdr = { .type = FD_TLS_EXT_ALPN,
319 7626 : .sz = (ushort)( in->alpn.bufsz+2 ) };
320 7626 : FD_TLS_ENCODE_SUB( fd_tls_encode_ext_hdr, &ext_hdr );
321 7626 : FD_TLS_ENCODE_SUB( fd_tls_encode_ext_alpn, &in->alpn );
322 7626 : }
323 :
324 : /* Add QUIC transport params */
325 :
326 9747 : if( in->quic_tp.buf ) {
327 6117 : ushort quic_tp_ext_type = FD_TLS_EXT_QUIC_TRANSPORT_PARAMS;
328 6117 : ushort quic_tp_ext_sz = (ushort)in->quic_tp.bufsz;
329 6117 : # define FIELDS( FIELD ) \
330 12234 : FIELD( 0, &quic_tp_ext_type, ushort, 1 ); \
331 12234 : FIELD( 1, &quic_tp_ext_sz, ushort, 1 ); \
332 12234 : FIELD( 2, in->quic_tp.buf, uchar, in->quic_tp.bufsz );
333 12234 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
334 6117 : # undef FIELDS
335 6117 : }
336 :
337 9747 : FD_STORE( ushort, extension_tot_sz, fd_ushort_bswap( (ushort)( (ulong)wire_laddr - extension_start ) ) );
338 9747 : return (long)( wire_laddr - (ulong)wire );
339 9747 : }
340 :
341 : /* Decode ServerHello (RFC 8446 Section 4.1.3) */
342 : long
343 : fd_tls_decode_server_hello( fd_tls_server_hello_t * out,
344 : uchar const * wire,
345 9426 : ulong wire_sz ) {
346 :
347 9426 : ulong wire_laddr = (ulong)wire;
348 :
349 : /* Decode static sized part of server hello */
350 :
351 9426 : ushort legacy_version; /* ==FD_TLS_VERSION_TLS12 */
352 9426 : uchar legacy_session_id_sz; /* 0 for QUIC, 0-32 for TCP */
353 9426 : ushort cipher_suite; /* ==FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256 */
354 9426 : uchar legacy_compression_method; /* ==0 */
355 :
356 9426 : # define FIELDS( FIELD ) \
357 18852 : FIELD( 0, &legacy_version, ushort, 1 ) \
358 18852 : FIELD( 1, &out->random[0], uchar, 32UL ) \
359 18852 : FIELD( 2, &legacy_session_id_sz, uchar, 1 )
360 18852 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
361 9426 : # undef FIELDS
362 :
363 : /* Skip legacy_session_id (echoed back for TCP middlebox compat) */
364 :
365 9426 : if( FD_UNLIKELY( legacy_session_id_sz > 32 ) )
366 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
367 9426 : if( FD_UNLIKELY( (ulong)legacy_session_id_sz > wire_sz ) )
368 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
369 9426 : out->session_id.buf = (uchar const *)wire_laddr;
370 9426 : out->session_id.bufsz = legacy_session_id_sz;
371 9426 : wire_laddr += legacy_session_id_sz;
372 9426 : wire_sz -= legacy_session_id_sz;
373 :
374 9426 : # define FIELDS( FIELD ) \
375 18852 : FIELD( 0, &cipher_suite, ushort, 1 ) \
376 18852 : FIELD( 1, &legacy_compression_method, uchar, 1 )
377 18852 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
378 9426 : # undef FIELDS
379 :
380 9426 : if( FD_UNLIKELY( ( legacy_version != FD_TLS_VERSION_TLS12 )
381 9426 : | ( legacy_compression_method != 0 ) ) )
382 0 : return -(long)FD_TLS_ALERT_PROTOCOL_VERSION;
383 :
384 9426 : out->cipher_suite = cipher_suite;
385 :
386 : /* Reject HelloRetryRequest (we only support X25519) */
387 :
388 9426 : if( FD_UNLIKELY( 0==memcmp( out->random, hello_retry_magic, 32 ) ) )
389 0 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
390 :
391 : /* Read extensions */
392 :
393 9426 : ulong seen = 0UL;
394 37704 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
395 : /* Read extension type and length */
396 18852 : ushort ext_type;
397 18852 : ushort ext_sz;
398 18852 : # define FIELDS( FIELD ) \
399 37704 : FIELD( 0, &ext_type, ushort, 1 ) \
400 37704 : FIELD( 1, &ext_sz, ushort, 1 )
401 37704 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
402 18852 : # undef FIELDS
403 :
404 : /* Bounds check extension data */
405 18852 : if( FD_UNLIKELY( ext_sz > wire_sz ) )
406 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
407 :
408 : /* RFC 8446 Section 4.2: at most one extension of each type */
409 18852 : if( ext_type<64 ) {
410 18846 : if( FD_UNLIKELY( seen & (1UL<<ext_type) ) ) return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
411 18840 : seen |= 1UL<<ext_type;
412 18840 : }
413 :
414 18846 : ulong next_field = wire_laddr + ext_sz;
415 18846 : ulong next_sz = wire_sz - ext_sz;
416 :
417 : /* Decode extension data */
418 18846 : uchar const * ext_data = (uchar const *)wire_laddr;
419 18846 : long ext_parse_res;
420 18846 : switch( ext_type ) {
421 9420 : case FD_TLS_EXT_SUPPORTED_VERSIONS: {
422 9420 : ushort chosen_version;
423 9420 : FD_TLS_DECODE_FIELD( &chosen_version, ushort );
424 9420 : ext_parse_res = 2L;
425 9420 : if( FD_UNLIKELY( chosen_version!=FD_TLS_VERSION_TLS13 ) )
426 0 : return -(long)FD_TLS_ALERT_PROTOCOL_VERSION;
427 9420 : break;
428 9420 : }
429 9420 : case FD_TLS_EXT_KEY_SHARE:
430 9417 : ext_parse_res = fd_tls_decode_key_share( &out->key_share, ext_data, ext_sz );
431 9417 : break;
432 9 : default:
433 : /* RFC 8446 Section 4.2: a ServerHello may only carry responses
434 : to extensions the client offered */
435 9 : return -(long)FD_TLS_ALERT_UNSUPPORTED_EXTENSION;
436 18846 : }
437 :
438 18837 : if( FD_UNLIKELY( ext_parse_res<0L ) )
439 0 : return ext_parse_res;
440 18837 : if( FD_UNLIKELY( ext_parse_res != (long)ext_sz ) )
441 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
442 :
443 18837 : wire_laddr = next_field;
444 18837 : wire_sz = next_sz;
445 18837 : }
446 9411 : FD_TLS_DECODE_LIST_END
447 :
448 : /* Check for required extensions. Without supported_versions this
449 : is a TLS 1.2 ServerHello (RFC 8446 Section 4.1.3). */
450 :
451 9411 : if( FD_UNLIKELY( !(seen & (1UL<<FD_TLS_EXT_SUPPORTED_VERSIONS)) ) )
452 3 : return -(long)FD_TLS_ALERT_PROTOCOL_VERSION;
453 9408 : if( FD_UNLIKELY( !out->key_share.has_x25519 ) )
454 3 : return -(long)FD_TLS_ALERT_MISSING_EXTENSION;
455 :
456 9405 : return (long)( wire_laddr - (ulong)wire );
457 9408 : }
458 :
459 : long
460 : fd_tls_encode_server_hello( fd_tls_server_hello_t const * in,
461 : uchar * wire,
462 6900 : ulong wire_sz ) {
463 :
464 6900 : ulong wire_laddr = (ulong)wire;
465 :
466 : /* Encode static sized part of server hello.
467 : (Assuming that session ID field is of a certain size) */
468 :
469 6900 : ushort legacy_version = FD_TLS_VERSION_TLS12;
470 6900 : uchar legacy_session_id_sz = (uchar)in->session_id.bufsz;
471 6900 : ushort cipher_suite = FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256;
472 6900 : uchar legacy_compression_method = 0;
473 :
474 6900 : # define FIELDS( FIELD ) \
475 13800 : FIELD( 0, &legacy_version, ushort, 1 ) \
476 13800 : FIELD( 1, &in->random[0], uchar, 32UL ) \
477 13800 : FIELD( 2, &legacy_session_id_sz, uchar, 1 ) \
478 13800 : FIELD( 3, in->session_id.buf, uchar, legacy_session_id_sz ) \
479 13800 : FIELD( 4, &cipher_suite, ushort, 1 ) \
480 13800 : FIELD( 5, &legacy_compression_method, uchar, 1 )
481 13800 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
482 6900 : # undef FIELDS
483 :
484 : /* Encode extensions */
485 :
486 6900 : ushort * extension_tot_sz = FD_TLS_SKIP_FIELD( ushort );
487 6900 : ulong extension_start = wire_laddr;
488 :
489 6900 : ushort ext_supported_versions_ext_type = FD_TLS_EXT_SUPPORTED_VERSIONS;
490 6900 : ushort ext_supported_versions[1] = { FD_TLS_VERSION_TLS13 };
491 6900 : ushort ext_supported_versions_ext_sz = sizeof(ext_supported_versions);
492 :
493 6900 : ushort ext_key_share_ext_type = FD_TLS_EXT_KEY_SHARE;
494 6900 : ushort ext_key_share_ext_sz = sizeof(ushort) + sizeof(ushort) + 32UL;
495 6900 : ushort ext_key_share_group = FD_TLS_GROUP_X25519;
496 6900 : ushort ext_key_share_sz = 32UL;
497 :
498 6900 : # define FIELDS( FIELD ) \
499 13800 : FIELD( 0, &ext_supported_versions_ext_type, ushort, 1 ) \
500 13800 : FIELD( 1, &ext_supported_versions_ext_sz, ushort, 1 ) \
501 13800 : FIELD( 2, ext_supported_versions, ushort, 1 ) \
502 13800 : FIELD( 3, &ext_key_share_ext_type, ushort, 1 ) \
503 13800 : FIELD( 4, &ext_key_share_ext_sz, ushort, 1 ) \
504 13800 : FIELD( 5, &ext_key_share_group, ushort, 1 ) \
505 13800 : FIELD( 6, &ext_key_share_sz, ushort, 1 ) \
506 13800 : FIELD( 7, &in->key_share.x25519[0], uchar, 32UL )
507 13800 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
508 6900 : # undef FIELDS
509 :
510 6900 : *extension_tot_sz = fd_ushort_bswap( (ushort)( (ulong)wire_laddr - extension_start ) );
511 6900 : return (long)( wire_laddr - (ulong)wire );
512 6900 : }
513 :
514 : long
515 : fd_tls_encode_hello_retry_request( fd_tls_server_hello_t const * in,
516 : uchar * wire,
517 192 : ulong wire_sz ) {
518 :
519 192 : ulong wire_laddr = (ulong)wire;
520 :
521 192 : ushort legacy_version = FD_TLS_VERSION_TLS12;
522 192 : uchar legacy_session_id_sz = (uchar)in->session_id.bufsz;
523 192 : ushort cipher_suite = FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256;
524 192 : uchar legacy_compression_method = 0;
525 :
526 192 : # define FIELDS( FIELD ) \
527 384 : FIELD( 0, &legacy_version, ushort, 1 ) \
528 384 : FIELD( 1, hello_retry_magic, uchar, 32UL ) \
529 384 : FIELD( 2, &legacy_session_id_sz, uchar, 1 ) \
530 384 : FIELD( 3, in->session_id.buf, uchar, legacy_session_id_sz ) \
531 384 : FIELD( 4, &cipher_suite, ushort, 1 ) \
532 384 : FIELD( 5, &legacy_compression_method, uchar, 1 )
533 384 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
534 192 : # undef FIELDS
535 :
536 : /* Encode extensions */
537 :
538 192 : ushort * extension_tot_sz = FD_TLS_SKIP_FIELD( ushort );
539 192 : ulong extension_start = wire_laddr;
540 :
541 192 : ushort ext_supported_versions_ext_type = FD_TLS_EXT_SUPPORTED_VERSIONS;
542 192 : ushort ext_supported_versions[1] = { FD_TLS_VERSION_TLS13 };
543 192 : ushort ext_supported_versions_ext_sz = sizeof(ext_supported_versions);
544 :
545 192 : ushort ext_key_share_ext_type = FD_TLS_EXT_KEY_SHARE;
546 192 : ushort ext_key_share_ext_sz = sizeof(ushort);
547 192 : ushort ext_key_share_group = FD_TLS_GROUP_X25519;
548 :
549 192 : # define FIELDS( FIELD ) \
550 384 : FIELD( 0, &ext_supported_versions_ext_type, ushort, 1 ) \
551 384 : FIELD( 1, &ext_supported_versions_ext_sz, ushort, 1 ) \
552 384 : FIELD( 2, ext_supported_versions, ushort, 1 ) \
553 384 : FIELD( 3, &ext_key_share_ext_type, ushort, 1 ) \
554 384 : FIELD( 4, &ext_key_share_ext_sz, ushort, 1 ) \
555 384 : FIELD( 5, &ext_key_share_group, ushort, 1 )
556 384 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
557 192 : # undef FIELDS
558 :
559 192 : *extension_tot_sz = fd_ushort_bswap( (ushort)( (ulong)wire_laddr - extension_start ) );
560 192 : return (long)( wire_laddr - (ulong)wire );
561 192 : }
562 :
563 : /* Decode EncryptedExtensions (RFC 8446 Section 4.3.1) */
564 : long
565 : fd_tls_decode_enc_ext( fd_tls_enc_ext_t * const out,
566 : uchar const * const wire,
567 9429 : ulong wire_sz ) {
568 :
569 9429 : ulong wire_laddr = (ulong)wire;
570 :
571 9429 : ulong seen = 0UL;
572 37716 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
573 13701 : ushort ext_type;
574 13701 : ushort ext_sz;
575 13701 : # define FIELDS( FIELD ) \
576 27402 : FIELD( 0, &ext_type, ushort, 1 ) \
577 27402 : FIELD( 1, &ext_sz, ushort, 1 )
578 27402 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
579 13701 : # undef FIELDS
580 :
581 : /* Bounds check extension data
582 : (list_stop declared by DECODE_LIST macro) */
583 13701 : if( FD_UNLIKELY( wire_laddr + ext_sz > list_stop ) )
584 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
585 :
586 : /* RFC 8446 Section 4.2: at most one extension of each type */
587 13701 : if( ext_type<64 ) {
588 13698 : if( FD_UNLIKELY( seen & (1UL<<ext_type) ) ) return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
589 13695 : seen |= 1UL<<ext_type;
590 13695 : }
591 :
592 13698 : switch( ext_type ) {
593 6 : case FD_TLS_EXT_SERVER_NAME:
594 6 : if( FD_UNLIKELY( ext_sz ) ) return -FD_TLS_ALERT_DECODE_ERROR;
595 6 : out->server_name = 1;
596 6 : break;
597 9 : case FD_TLS_EXT_SUPPORTED_GROUPS: {
598 : /* RFC 8446 Section 4.2.7 explicitly permits this in EE. */
599 9 : fd_tls_ext_supported_groups_t groups = {0};
600 9 : long res = fd_tls_decode_ext_supported_groups( &groups, (uchar const *)wire_laddr, ext_sz );
601 9 : if( FD_UNLIKELY( res<0L ) ) return res;
602 9 : if( FD_UNLIKELY( res!=(long)ext_sz ) ) return -FD_TLS_ALERT_DECODE_ERROR;
603 9 : break;
604 9 : }
605 7596 : case FD_TLS_EXT_ALPN: {
606 7596 : long res = fd_tls_decode_ext_alpn( &out->alpn, (uchar const *)wire_laddr, ext_sz );
607 7596 : if( FD_UNLIKELY( res<0L ) )
608 0 : return res;
609 7596 : if( FD_UNLIKELY( res!=(long)ext_sz ) )
610 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
611 7596 : if( FD_UNLIKELY( out->alpn.bufsz != 1UL+out->alpn.buf[0] ) )
612 3 : return -FD_TLS_ALERT_DECODE_ERROR;
613 7593 : break;
614 7596 : }
615 7593 : case FD_TLS_EXT_QUIC_TRANSPORT_PARAMS:
616 6075 : if( FD_UNLIKELY( ext_sz > FD_TLS_EXT_QUIC_PARAMS_SZ_MAX ) )
617 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
618 6075 : out->quic_tp.buf = (void *)wire_laddr;
619 6075 : out->quic_tp.bufsz = (ushort)ext_sz;
620 6075 : break;
621 12 : default:
622 12 : return -(long)FD_TLS_ALERT_UNSUPPORTED_EXTENSION;
623 13698 : }
624 :
625 13683 : wire_laddr += ext_sz;
626 13683 : wire_sz -= ext_sz;
627 13683 : }
628 9411 : FD_TLS_DECODE_LIST_END
629 :
630 9411 : return (long)( wire_laddr - (ulong)wire );
631 9429 : }
632 :
633 : /* Decode CertificateRequest (RFC 8446 Section 4.3.2) */
634 : long
635 : fd_tls_decode_cert_req( fd_tls_ext_signature_algorithms_t * out,
636 : uchar const * wire,
637 8325 : ulong wire_sz ) {
638 :
639 8325 : ulong wire_laddr = (ulong)wire;
640 :
641 : /* certificate_request_context is empty outside of post-handshake
642 : authentication, which is not supported */
643 8325 : uchar ctx_sz;
644 8325 : FD_TLS_DECODE_FIELD( &ctx_sz, uchar );
645 8325 : if( FD_UNLIKELY( ctx_sz ) )
646 3 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
647 :
648 8322 : ulong seen = 0UL;
649 33285 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
650 10362 : ushort ext_type;
651 10362 : ushort ext_sz;
652 10362 : # define FIELDS( FIELD ) \
653 20724 : FIELD( 0, &ext_type, ushort, 1 ) \
654 20724 : FIELD( 1, &ext_sz, ushort, 1 )
655 20724 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
656 10362 : # undef FIELDS
657 :
658 10362 : if( FD_UNLIKELY( ext_sz > wire_sz ) )
659 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
660 :
661 : /* RFC 8446 Section 4.2: at most one extension of each type */
662 10362 : if( ext_type<64 ) {
663 10359 : if( FD_UNLIKELY( seen & (1UL<<ext_type) ) ) return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
664 10356 : seen |= 1UL<<ext_type;
665 10356 : }
666 :
667 10359 : long ext_parse_res;
668 10359 : switch( ext_type ) {
669 8313 : case FD_TLS_EXT_SIGNATURE_ALGORITHMS:
670 8313 : ext_parse_res = fd_tls_decode_ext_signature_algorithms( out, (uchar const *)wire_laddr, ext_sz );
671 8313 : break;
672 2046 : default:
673 : /* Ignore everything else. certificate_authorities, oid_filters
674 : and signature_algorithms_cert do not change which certificate
675 : we send (we only have one), and extensions that RFC 8446
676 : Section 4.2 forbids here are tolerated rather than rejected
677 : with illegal_parameter. */
678 2046 : ext_parse_res = (long)ext_sz;
679 2046 : break;
680 10359 : }
681 10359 : if( FD_UNLIKELY( ext_parse_res<0L ) )
682 3 : return ext_parse_res;
683 10356 : if( FD_UNLIKELY( ext_parse_res != (long)ext_sz ) )
684 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
685 :
686 10356 : wire_laddr += ext_sz;
687 10356 : wire_sz -= ext_sz;
688 10356 : }
689 8313 : FD_TLS_DECODE_LIST_END
690 :
691 : /* signature_algorithms MUST be specified */
692 8313 : if( FD_UNLIKELY( !(seen & (1UL<<FD_TLS_EXT_SIGNATURE_ALGORITHMS)) ) )
693 6 : return -(long)FD_TLS_ALERT_MISSING_EXTENSION;
694 :
695 8307 : return (long)( wire_laddr - (ulong)wire );
696 8313 : }
697 :
698 : long
699 : fd_tls_encode_cert_x509( uchar const * x509,
700 : ulong x509_sz,
701 : uchar * wire,
702 14172 : ulong wire_sz ) {
703 :
704 14172 : ulong wire_laddr = (ulong)wire;
705 :
706 : /* TLS Record Header */
707 14172 : uchar msg_type = (uchar)FD_TLS_MSG_CERT;
708 :
709 : /* TLS Certificate Message header preceding X.509 data */
710 :
711 : /* All size prefixes known in advance */
712 14172 : fd_tls_u24_t msg_sz = fd_uint_to_tls_u24( (uint)( x509_sz + 9UL ) );
713 14172 : fd_tls_u24_t cert_list_sz = fd_uint_to_tls_u24( (uint)( x509_sz + 5UL ) );
714 14172 : fd_tls_u24_t cert_sz = fd_uint_to_tls_u24( (uint)( x509_sz ) );
715 :
716 : /* zero sz certificate_request_context
717 : (Server certificate never has a request context) */
718 14172 : uchar certificate_request_context_sz = (uchar)0;
719 :
720 : /* No certificate extensions */
721 14172 : ushort ext_sz = (ushort)0;
722 :
723 14172 : # define FIELDS( FIELD ) \
724 28344 : FIELD( 0, &msg_type, uchar, 1 ) \
725 28344 : FIELD( 1, &msg_sz, tls_u24, 1 ) \
726 28344 : FIELD( 2, &certificate_request_context_sz, uchar, 1 ) \
727 28344 : FIELD( 3, &cert_list_sz, tls_u24, 1 ) \
728 28344 : FIELD( 4, &cert_sz, tls_u24, 1 ) \
729 28344 : FIELD( 5, x509, uchar, x509_sz ) \
730 28344 : FIELD( 6, &ext_sz, ushort, 1 )
731 28344 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
732 14172 : # undef FIELDS
733 :
734 14172 : return (long)( wire_laddr - (ulong)wire );
735 14172 : }
736 :
737 : long
738 : fd_tls_encode_enc_ext( fd_tls_enc_ext_t const * in,
739 : uchar * wire,
740 6894 : ulong wire_sz ) {
741 :
742 6894 : ulong wire_laddr = (ulong)wire;
743 :
744 : /* ALPN */
745 :
746 6894 : if( in->alpn.bufsz ) {
747 6363 : fd_tls_ext_hdr_t ext_hdr = { .type = FD_TLS_EXT_ALPN,
748 6363 : .sz = (ushort)( in->alpn.bufsz+2 ) };
749 6363 : FD_TLS_ENCODE_SUB( fd_tls_encode_ext_hdr, &ext_hdr );
750 6363 : FD_TLS_ENCODE_SUB( fd_tls_encode_ext_alpn, &in->alpn );
751 6363 : }
752 :
753 : /* QUIC transport params */
754 :
755 6894 : if( in->quic_tp.buf ) {
756 6072 : ushort ext_type = FD_TLS_EXT_QUIC_TRANSPORT_PARAMS;
757 6072 : ushort ext_sz = (ushort)in->quic_tp.bufsz;
758 6072 : # define FIELDS( FIELD ) \
759 12144 : FIELD( 0, &ext_type, ushort, 1 ) \
760 12144 : FIELD( 1, &ext_sz, ushort, 1 ) \
761 12144 : FIELD( 2, in->quic_tp.buf, uchar, in->quic_tp.bufsz )
762 12144 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
763 6072 : # undef FIELDS
764 6072 : }
765 :
766 6894 : return (long)( wire_laddr - (ulong)wire );
767 6894 : }
768 :
769 : /* Decode CertificateVerify (RFC 8446 Section 4.4.3) */
770 : long
771 : fd_tls_decode_cert_verify( fd_tls_cert_verify_t * out,
772 : uchar const * wire,
773 16197 : ulong wire_sz ) {
774 :
775 16197 : ulong wire_laddr = (ulong)wire;
776 :
777 16197 : ushort sig_sz;
778 16197 : # define FIELDS( FIELD ) \
779 32394 : FIELD( 0, &out->algorithm, ushort, 1 ) \
780 32394 : FIELD( 1, &sig_sz, ushort, 1 )
781 32394 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
782 16197 : # undef FIELDS
783 :
784 : /* Validate signature algorithm and length */
785 :
786 16197 : switch( out->algorithm ) {
787 14379 : case FD_TLS_SIGNATURE_ED25519:
788 14379 : if( FD_UNLIKELY( sig_sz != 64U ) )
789 0 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
790 14379 : break;
791 14379 : case FD_TLS_SIGNATURE_ECDSA_SECP256R1_SHA256:
792 : /* ECDSA DER-encoded signatures are variable length, max 73 */
793 1296 : if( FD_UNLIKELY( sig_sz > 73U || sig_sz < 8U ) )
794 0 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
795 1296 : break;
796 1296 : case FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA256:
797 498 : case FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA384:
798 522 : case FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA512:
799 : /* Signature is the size of the modulus */
800 522 : if( FD_UNLIKELY( sig_sz > FD_RSA_MOD_SZ_MAX || sig_sz < FD_RSA_MOD_BITS_MIN/8UL ) )
801 9 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
802 513 : break;
803 513 : default:
804 0 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
805 16197 : }
806 :
807 : /* Read signature bytes */
808 :
809 16188 : if( FD_UNLIKELY( sig_sz > wire_sz ) )
810 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
811 16188 : fd_memcpy( out->signature, (void const *)wire_laddr, sig_sz );
812 16188 : out->signature_len = sig_sz;
813 16188 : wire_laddr += sig_sz;
814 16188 : wire_sz -= sig_sz;
815 :
816 16188 : return (long)( wire_laddr - (ulong)wire );
817 16188 : }
818 :
819 : long
820 : fd_tls_encode_cert_verify( fd_tls_cert_verify_t const * in,
821 : uchar * wire,
822 14163 : ulong wire_sz ) {
823 :
824 14163 : ulong wire_laddr = (ulong)wire;
825 :
826 14163 : ushort sig_sz = in->signature_len;
827 14163 : # define FIELDS( FIELD ) \
828 28326 : FIELD( 0, &in->algorithm, ushort, 1 ) \
829 28326 : FIELD( 1, &sig_sz, ushort, 1 )
830 28326 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
831 14163 : # undef FIELDS
832 :
833 14163 : if( FD_UNLIKELY( sig_sz > wire_sz ) )
834 0 : return -(long)FD_TLS_ALERT_INTERNAL_ERROR;
835 14163 : fd_memcpy( (void *)wire_laddr, in->signature, sig_sz );
836 14163 : wire_laddr += sig_sz;
837 14163 : wire_sz -= sig_sz;
838 :
839 14163 : return (long)( wire_laddr - (ulong)wire );
840 14163 : }
841 :
842 : /* Decode server_name extension (RFC 6066 Section 3) */
843 : long
844 : fd_tls_decode_ext_server_name( fd_tls_ext_server_name_t * out,
845 : uchar const * wire,
846 882 : ulong wire_sz ) {
847 :
848 882 : ulong wire_laddr = (ulong)wire;
849 :
850 : /* TLS v1.3 server name lists practically always have one element. */
851 :
852 882 : if( FD_UNLIKELY( wire_sz<2UL || !FD_LOAD( ushort, wire ) ) )
853 3 : return -FD_TLS_ALERT_DECODE_ERROR;
854 879 : uchar seen[ 32 ] = {0};
855 3516 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
856 : /* Read type and length */
857 879 : uchar name_type;
858 879 : ushort name_sz;
859 879 : # define FIELDS( FIELD ) \
860 1758 : FIELD( 0, &name_type, uchar, 1 ) \
861 1758 : FIELD( 1, &name_sz, ushort, 1 )
862 1758 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
863 879 : # undef FIELDS
864 :
865 : /* Bounds check name */
866 879 : if( FD_UNLIKELY( !name_sz || wire_laddr + name_sz > list_stop ) )
867 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
868 879 : uchar mask = (uchar)( 1U<<(name_type&7U) );
869 879 : if( FD_UNLIKELY( seen[ name_type>>3 ]&mask ) ) return -FD_TLS_ALERT_ILLEGAL_PARAMETER;
870 879 : seen[ name_type>>3 ] |= mask;
871 :
872 : /* Decode name on first use */
873 879 : if( ( ( name_type == FD_TLS_SERVER_NAME_TYPE_DNS )
874 879 : & ( name_sz < 254 )
875 879 : & ( out->host_name_len == 0 ) ) ) {
876 879 : out->host_name_len = (uchar)name_sz;
877 879 : memcpy( out->host_name, (uchar const *)wire_laddr, name_sz );
878 879 : out->host_name[ name_sz ] = '\0';
879 879 : }
880 :
881 : /* Seek to next name */
882 879 : wire_laddr += name_sz;
883 879 : wire_sz -= name_sz;
884 879 : }
885 879 : FD_TLS_DECODE_LIST_END
886 :
887 879 : return (long)( wire_laddr - (ulong)wire );
888 879 : }
889 :
890 : /* Decode supported_groups extension (RFC 8446 Section 4.2.7) */
891 : long
892 : fd_tls_decode_ext_supported_groups( fd_tls_ext_supported_groups_t * out,
893 : uchar const * wire,
894 7215 : ulong wire_sz ) {
895 :
896 7215 : ulong wire_laddr = (ulong)wire;
897 :
898 7215 : if( FD_UNLIKELY( wire_sz<2UL || !FD_LOAD( ushort, wire ) ) )
899 3 : return -FD_TLS_ALERT_DECODE_ERROR;
900 28848 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(ushort) ) {
901 7803 : ushort group;
902 7803 : FD_TLS_DECODE_FIELD( &group, ushort );
903 7803 : switch( group ) {
904 7200 : case FD_TLS_GROUP_X25519:
905 7200 : out->x25519 = 1;
906 7200 : break;
907 603 : default:
908 : /* Ignore unsupported groups ... */
909 603 : break;
910 7803 : }
911 7803 : }
912 7212 : FD_TLS_DECODE_LIST_END
913 :
914 7212 : return (long)( wire_laddr - (ulong)wire );
915 7212 : }
916 :
917 : /* Decode supported_versions extension (RFC 8446 Section 4.2.1) */
918 : long
919 : fd_tls_decode_ext_supported_versions( fd_tls_ext_supported_versions_t * out,
920 : uchar const * wire,
921 7194 : ulong wire_sz ) {
922 :
923 7194 : ulong wire_laddr = (ulong)wire;
924 :
925 7194 : if( FD_UNLIKELY( !wire_sz || !wire[0] ) ) return -FD_TLS_ALERT_DECODE_ERROR;
926 28764 : FD_TLS_DECODE_LIST_BEGIN( uchar, alignof(ushort) ) {
927 8055 : ushort group;
928 8055 : FD_TLS_DECODE_FIELD( &group, ushort );
929 8055 : switch( group ) {
930 7191 : case FD_TLS_VERSION_TLS13:
931 7191 : out->tls13 = 1;
932 7191 : break;
933 864 : default:
934 : /* Ignore unsupported TLS versions ... */
935 864 : break;
936 8055 : }
937 8055 : }
938 7191 : FD_TLS_DECODE_LIST_END
939 :
940 7191 : return (long)( wire_laddr - (ulong)wire );
941 7191 : }
942 :
943 : /* Decode signature_algorithms extension (RFC 8446 Section 4.2.3) */
944 : long
945 : fd_tls_decode_ext_signature_algorithms( fd_tls_ext_signature_algorithms_t * out,
946 : uchar const * wire,
947 15732 : ulong wire_sz ) {
948 :
949 15732 : ulong wire_laddr = (ulong)wire;
950 :
951 15732 : if( FD_UNLIKELY( wire_sz<2UL || !FD_LOAD( ushort, wire ) ) )
952 6 : return -FD_TLS_ALERT_DECODE_ERROR;
953 62904 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(ushort) ) {
954 51420 : ushort group;
955 51420 : FD_TLS_DECODE_FIELD( &group, ushort );
956 51420 : switch( group ) {
957 15711 : case FD_TLS_SIGNATURE_ED25519:
958 15711 : out->ed25519 = 1;
959 15711 : break;
960 2967 : case FD_TLS_SIGNATURE_ECDSA_SECP256R1_SHA256:
961 2967 : out->ecdsa_secp256r1_sha256 = 1;
962 2967 : break;
963 2739 : case FD_TLS_SIGNATURE_ECDSA_SECP384R1_SHA384:
964 2739 : out->ecdsa_secp384r1_sha384 = 1;
965 2739 : break;
966 2739 : case FD_TLS_SIGNATURE_RSA_PKCS1_SHA256:
967 2739 : out->rsa_pkcs1_sha256 = 1;
968 2739 : break;
969 2739 : case FD_TLS_SIGNATURE_RSA_PKCS1_SHA384:
970 2739 : out->rsa_pkcs1_sha384 = 1;
971 2739 : break;
972 2739 : case FD_TLS_SIGNATURE_RSA_PKCS1_SHA512:
973 2739 : out->rsa_pkcs1_sha512 = 1;
974 2739 : break;
975 2739 : case FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA256:
976 2739 : out->rsa_pss_rsae_sha256 = 1;
977 2739 : break;
978 2739 : case FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA384:
979 2739 : out->rsa_pss_rsae_sha384 = 1;
980 2739 : break;
981 2739 : case FD_TLS_SIGNATURE_RSA_PSS_RSAE_SHA512:
982 2739 : out->rsa_pss_rsae_sha512 = 1;
983 2739 : break;
984 13569 : default:
985 : /* Ignore unsupported signature algorithms ... */
986 13569 : break;
987 51420 : }
988 51420 : }
989 15726 : FD_TLS_DECODE_LIST_END
990 :
991 15726 : return (long)( wire_laddr - (ulong)wire );
992 15726 : }
993 :
994 : long
995 : fd_tls_decode_key_share( fd_tls_key_share_t * out,
996 : uchar const * wire,
997 16614 : ulong wire_sz ) {
998 :
999 16614 : ulong wire_laddr = (ulong)wire;
1000 :
1001 : /* Read type and length */
1002 16614 : ushort group;
1003 16614 : ushort kex_data_sz;
1004 16614 : # define FIELDS( FIELD ) \
1005 33228 : FIELD( 0, &group, ushort, 1 ) \
1006 33228 : FIELD( 1, &kex_data_sz, ushort, 1 )
1007 33228 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
1008 16614 : # undef FIELDS
1009 :
1010 : /* Bounds check */
1011 16614 : if( FD_UNLIKELY( !kex_data_sz || kex_data_sz > wire_sz ) )
1012 3 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
1013 :
1014 16611 : switch( group ) {
1015 16407 : case FD_TLS_GROUP_X25519:
1016 16407 : if( FD_UNLIKELY( kex_data_sz != 32UL ) )
1017 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
1018 : /* RFC 8446 Section 4.2.8: at most one KeyShareEntry per group */
1019 16407 : if( FD_UNLIKELY( out->has_x25519 ) )
1020 3 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
1021 16404 : out->has_x25519 = 1;
1022 16404 : memcpy( out->x25519, (uchar const *)wire_laddr, 32UL );
1023 16404 : break;
1024 204 : default:
1025 : /* Ignore unsupported key share groups ... */
1026 204 : break;
1027 16611 : }
1028 :
1029 : /* Seek to next group */
1030 16608 : wire_laddr += kex_data_sz;
1031 16608 : wire_sz -= kex_data_sz;
1032 :
1033 16608 : return (long)( wire_laddr - (ulong)wire );
1034 16611 : }
1035 :
1036 : long
1037 : fd_tls_decode_key_share_list( fd_tls_key_share_t * out,
1038 : uchar const * wire,
1039 7200 : ulong wire_sz ) {
1040 :
1041 7200 : ulong wire_laddr = (ulong)wire;
1042 :
1043 28800 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
1044 7197 : FD_TLS_DECODE_SUB( fd_tls_decode_key_share, out );
1045 7197 : }
1046 7194 : FD_TLS_DECODE_LIST_END
1047 :
1048 7194 : return (long)( wire_laddr - (ulong)wire );
1049 7200 : }
1050 :
1051 : long
1052 : fd_tls_decode_ext_opaque( fd_tls_ext_opaque_t * const out,
1053 : uchar const * const wire,
1054 20160 : ulong wire_sz ) {
1055 20160 : out->buf = wire;
1056 20160 : out->bufsz = wire_sz;
1057 20160 : return (long)wire_sz;
1058 20160 : }
1059 :
1060 : long
1061 : fd_tls_decode_ext_alpn( fd_tls_ext_alpn_t * const out,
1062 : uchar const * const wire,
1063 14085 : ulong wire_sz ) {
1064 14085 : ulong wire_laddr = (ulong)wire;
1065 14085 : ushort alpn_sz;
1066 14085 : FD_TLS_DECODE_FIELD( &alpn_sz, ushort );
1067 14085 : if( FD_UNLIKELY( (ulong)alpn_sz != wire_sz ) )
1068 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
1069 14085 : if( FD_UNLIKELY( alpn_sz<2U ) ) return -FD_TLS_ALERT_DECODE_ERROR;
1070 14082 : uchar const * list = (uchar const *)wire_laddr;
1071 28566 : for( ulong off=0UL; off<wire_sz; ) {
1072 14490 : ulong len = list[ off++ ];
1073 14490 : if( FD_UNLIKELY( !len || len>wire_sz-off ) ) return -FD_TLS_ALERT_DECODE_ERROR;
1074 14484 : off += len;
1075 14484 : }
1076 14076 : return 2L + (long)fd_tls_decode_ext_opaque( out, (uchar const *)wire_laddr, wire_sz );
1077 14082 : }
1078 :
1079 : long
1080 : fd_tls_encode_ext_alpn( fd_tls_ext_alpn_t const * in,
1081 : uchar * wire,
1082 13989 : ulong wire_sz ) {
1083 13989 : ulong sz = 2UL + in->bufsz;
1084 13989 : if( FD_UNLIKELY( sz>wire_sz ) )
1085 0 : return -(long)FD_TLS_ALERT_INTERNAL_ERROR;
1086 13989 : wire[0] = (uchar)( (in->bufsz >> 8)&0xFF );
1087 13989 : wire[1] = (uchar)( in->bufsz &0xFF );
1088 13989 : fd_memcpy( wire+2UL, in->buf, in->bufsz );
1089 13989 : return (long)sz;
1090 13989 : }
1091 :
1092 : static long
1093 : fd_tls_extract_cert_pubkey_( fd_tls_extract_cert_pubkey_res_t * res,
1094 : uchar const * cert_chain,
1095 17061 : ulong cert_chain_sz ) {
1096 :
1097 17061 : fd_memset( res, 0, sizeof(fd_tls_extract_cert_pubkey_res_t) );
1098 :
1099 17061 : ulong wire_laddr = (ulong)cert_chain;
1100 17061 : ulong wire_sz = cert_chain_sz;
1101 :
1102 : /* Initial-handshake Certificate messages always have empty context. */
1103 17061 : uchar const * opaque_sz = FD_TLS_SKIP_FIELD( uchar );
1104 17049 : if( FD_UNLIKELY( *opaque_sz ) ) return -FD_TLS_ALERT_ILLEGAL_PARAMETER;
1105 :
1106 : /* Get first entry of certificate chain
1107 : CertificateEntry certificate_list<0..2^24-1> */
1108 17046 : fd_tls_u24_t const * cert_list_sz_be = FD_TLS_SKIP_FIELD( fd_tls_u24_t );
1109 17028 : fd_tls_u24_t cert_list_sz_ = fd_tls_u24_bswap( *cert_list_sz_be );
1110 17028 : uint cert_list_sz = fd_tls_u24_to_uint( cert_list_sz_ );
1111 17028 : if( FD_UNLIKELY( cert_list_sz!=wire_sz ) ) return -FD_TLS_ALERT_DECODE_ERROR;
1112 16257 : if( FD_UNLIKELY( cert_list_sz==0U ) ) {
1113 27 : res->alert = FD_TLS_ALERT_BAD_CERTIFICATE;
1114 27 : res->reason = FD_TLS_REASON_CERT_CHAIN_EMPTY;
1115 27 : return -1L;
1116 27 : }
1117 :
1118 : /* Validate every entry before extracting the leaf key, independently
1119 : of whether the caller requests X.509 chain authentication. */
1120 16230 : uchar const * cert = NULL;
1121 16230 : ulong cert_sz = 0UL;
1122 35061 : while( wire_sz ) {
1123 18840 : fd_tls_u24_t const * sz_be = FD_TLS_SKIP_FIELD( fd_tls_u24_t );
1124 18840 : ulong sz = fd_tls_u24_to_uint( fd_tls_u24_bswap( *sz_be ) );
1125 18840 : if( FD_UNLIKELY( !sz || sz>wire_sz ) ) return -FD_TLS_ALERT_DECODE_ERROR;
1126 18837 : if( !cert ) {
1127 16230 : cert = (uchar const *)wire_laddr;
1128 16230 : cert_sz = sz;
1129 16230 : }
1130 18837 : wire_laddr += sz;
1131 18837 : wire_sz -= sz;
1132 : /* We never solicit CertificateEntry extensions (RFC 8446 Section
1133 : 4.4.2), so the extensions vector must be empty */
1134 18837 : ushort const * ext_sz_be = FD_TLS_SKIP_FIELD( ushort );
1135 18834 : ulong ext_sz = fd_ushort_bswap( FD_LOAD( ushort, ext_sz_be ) );
1136 18834 : if( FD_UNLIKELY( ext_sz > wire_sz ) ) return -(long)FD_TLS_ALERT_DECODE_ERROR;
1137 18831 : if( FD_UNLIKELY( ext_sz ) ) return -(long)FD_TLS_ALERT_UNSUPPORTED_EXTENSION;
1138 18831 : }
1139 :
1140 16221 : if( FD_UNLIKELY( fd_x509_extract_pubkey( cert, cert_sz, &res->pubkey,
1141 16221 : &res->pubkey_len, &res->key_type ) ) ) {
1142 0 : res->pubkey = NULL;
1143 0 : res->alert = FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE;
1144 0 : res->reason = FD_TLS_REASON_X509_PARSE;
1145 0 : return -1L;
1146 0 : }
1147 :
1148 16221 : return 0L;
1149 16221 : }
1150 :
1151 : fd_tls_extract_cert_pubkey_res_t
1152 : fd_tls_extract_cert_pubkey( uchar const * cert_chain,
1153 17061 : ulong cert_chain_sz ) {
1154 17061 : fd_tls_extract_cert_pubkey_res_t res;
1155 17061 : long ret = fd_tls_extract_cert_pubkey_( &res, cert_chain, cert_chain_sz );
1156 17061 : if( FD_UNLIKELY( ret<0L && !res.alert ) ) {
1157 813 : res.alert = (uint)(-ret);
1158 813 : res.reason = FD_TLS_REASON_CERT_PARSE;
1159 813 : }
1160 17061 : return res;
1161 17061 : }
|