Line data Source code
1 : #include "fd_tls.h"
2 : #include "fd_tls_proto.h"
3 : #include "fd_tls_serde.h"
4 : #include "fd_tls_asn1.h"
5 : #include "../../ballet/x509/fd_x509_mock.h"
6 :
7 : typedef struct fd_tls_u24 tls_u24; /* code generator helper */
8 :
9 : /* hello_retry_magic is the RFC 8446 hardcoded value of the 'random' field of a RetryHelloRequest */
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 : long
35 : fd_tls_decode_client_hello( fd_tls_client_hello_t * out,
36 : uchar const * const wire,
37 6027 : ulong wire_sz ) {
38 :
39 6027 : ulong wire_laddr = (ulong)wire;
40 :
41 : /* Decode static sized part of client hello.
42 : (Assuming that session ID field is of a certain size) */
43 :
44 6027 : ushort legacy_version; /* ==FD_TLS_VERSION_TLS12 */
45 6027 : uchar legacy_session_id_sz; /* ==0 */
46 :
47 6027 : # define FIELDS( FIELD ) \
48 12054 : FIELD( 0, &legacy_version, ushort, 1 ) \
49 12054 : FIELD( 1, &out->random[0], uchar, 32UL ) \
50 12054 : FIELD( 2, &legacy_session_id_sz, uchar, 1 )
51 12054 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
52 6027 : # undef FIELDS
53 :
54 6027 : if( FD_UNLIKELY( ( legacy_session_id_sz > 32 ) |
55 6027 : ( wire_sz < legacy_session_id_sz ) ) )
56 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
57 :
58 6027 : out->session_id.buf = (void *)wire_laddr;
59 6027 : out->session_id.bufsz = legacy_session_id_sz;
60 6027 : wire_laddr += legacy_session_id_sz;
61 6027 : wire_sz -= legacy_session_id_sz;
62 :
63 : /* Decode cipher suite list */
64 :
65 24108 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(ushort) ) {
66 6054 : ushort cipher_suite;
67 6054 : FD_TLS_DECODE_FIELD( &cipher_suite, ushort );
68 :
69 6054 : switch( cipher_suite ) {
70 6024 : case FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256:
71 6024 : out->cipher_suites.aes_128_gcm_sha256 = 1;
72 6024 : break;
73 30 : default:
74 : /* Ignore unsupported cipher suites ... */
75 30 : break;
76 6054 : }
77 6054 : }
78 6027 : FD_TLS_DECODE_LIST_END
79 :
80 : /* Decode next static sized part of client hello */
81 :
82 6027 : uchar legacy_compression_method_cnt; /* == 1 */
83 6027 : uchar legacy_compression_methods[ 1 ]; /* =={0} */
84 :
85 6027 : # define FIELDS( FIELD ) \
86 12054 : FIELD( 5, &legacy_compression_method_cnt, uchar, 1 ) \
87 12054 : FIELD( 6, &legacy_compression_methods[0], uchar, 1 )
88 12054 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
89 6027 : # undef FIELDS
90 :
91 6027 : if( FD_UNLIKELY( ( legacy_compression_method_cnt != 1 )
92 6027 : | ( legacy_compression_methods[0] != 0 ) ) )
93 0 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
94 :
95 : /* Read extensions */
96 :
97 36183 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
98 : /* Read extension type and length */
99 36183 : ushort ext_type;
100 36183 : ushort ext_sz;
101 36183 : # define FIELDS( FIELD ) \
102 72366 : FIELD( 0, &ext_type, ushort, 1 ) \
103 72366 : FIELD( 1, &ext_sz, ushort, 1 )
104 72366 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
105 36183 : # undef FIELDS
106 :
107 : /* Bounds check extension data */
108 36183 : if( FD_UNLIKELY( ext_sz > wire_sz ) )
109 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
110 :
111 : /* Decode extension data */
112 36183 : uchar const * ext_data = (uchar const *)wire_laddr;
113 36183 : long ext_parse_res;
114 36183 : switch( ext_type ) {
115 6027 : case FD_TLS_EXT_SUPPORTED_VERSIONS:
116 6027 : ext_parse_res = fd_tls_decode_ext_supported_versions( &out->supported_versions, ext_data, ext_sz );
117 6027 : break;
118 3 : case FD_TLS_EXT_SERVER_NAME:
119 3 : ext_parse_res = fd_tls_decode_ext_server_name( &out->server_name, ext_data, ext_sz );
120 3 : break;
121 6027 : case FD_TLS_EXT_SUPPORTED_GROUPS:
122 6027 : ext_parse_res = fd_tls_decode_ext_supported_groups( &out->supported_groups, ext_data, ext_sz );
123 6027 : break;
124 6027 : case FD_TLS_EXT_SIGNATURE_ALGORITHMS:
125 6027 : ext_parse_res = fd_tls_decode_ext_signature_algorithms( &out->signature_algorithms, ext_data, ext_sz );
126 6027 : break;
127 6027 : case FD_TLS_EXT_KEY_SHARE:
128 6027 : ext_parse_res = fd_tls_decode_key_share_list( &out->key_share, ext_data, ext_sz );
129 6027 : break;
130 3 : case FD_TLS_EXT_SERVER_CERT_TYPE:
131 3 : ext_parse_res = fd_tls_decode_ext_cert_type_list( &out->server_cert_types, ext_data, ext_sz );
132 3 : break;
133 3 : case FD_TLS_EXT_CLIENT_CERT_TYPE:
134 3 : ext_parse_res = fd_tls_decode_ext_cert_type_list( &out->client_cert_types, ext_data, ext_sz );
135 3 : break;
136 6024 : case FD_TLS_EXT_QUIC_TRANSPORT_PARAMS:
137 6024 : ext_parse_res = fd_tls_decode_ext_quic_tp( &out->quic_tp, ext_data, ext_sz );
138 6024 : break;
139 6024 : case FD_TLS_EXT_ALPN:
140 6024 : ext_parse_res = fd_tls_decode_ext_alpn( &out->alpn, ext_data, ext_sz );
141 6024 : break;
142 18 : default:
143 18 : ext_parse_res = (long)ext_sz;
144 18 : break;
145 36183 : }
146 36183 : if( FD_UNLIKELY( ext_parse_res<0L ) )
147 0 : return ext_parse_res;
148 36183 : if( FD_UNLIKELY( ext_parse_res != (long)ext_sz ) )
149 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
150 :
151 : /* Seek to next extension */
152 36183 : wire_laddr += ext_sz;
153 36183 : wire_sz -= ext_sz;
154 36183 : }
155 6027 : FD_TLS_DECODE_LIST_END
156 :
157 6027 : return (long)( wire_laddr - (ulong)wire );
158 6027 : }
159 :
160 : long
161 : fd_tls_encode_client_hello( fd_tls_client_hello_t const * in,
162 : uchar * wire,
163 6024 : ulong wire_sz ) {
164 :
165 6024 : ulong wire_laddr = (ulong)wire;
166 :
167 : /* Encode static sized part of client hello */
168 :
169 6024 : ushort legacy_version = FD_TLS_VERSION_TLS12;
170 6024 : uchar legacy_session_id_sz = 0;
171 6024 : ushort cipher_suite_sz = 1*sizeof(ushort);
172 6024 : ushort cipher_suites[1] = { FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256 };
173 6024 : uchar legacy_comp_method_sz = 1;
174 6024 : uchar legacy_comp_method[1] = {0};
175 :
176 6024 : # define FIELDS( FIELD ) \
177 12048 : FIELD( 0, &legacy_version, ushort, 1 ) \
178 12048 : FIELD( 1, in->random, uchar, 32UL ) \
179 12048 : FIELD( 2, &legacy_session_id_sz, uchar, 1 ) \
180 12048 : FIELD( 3, &cipher_suite_sz, ushort, 1 ) \
181 12048 : FIELD( 4, cipher_suites, ushort, 1 ) \
182 12048 : FIELD( 5, &legacy_comp_method_sz, uchar, 1 ) \
183 12048 : FIELD( 6, legacy_comp_method, uchar, 1 )
184 12048 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
185 6024 : # undef FIELDS
186 :
187 : /* Encode extensions */
188 :
189 6024 : ushort * extension_tot_sz = FD_TLS_SKIP_FIELD( ushort );
190 0 : ulong extension_start = wire_laddr;
191 :
192 6024 : ushort ext_supported_versions_ext_type = FD_TLS_EXT_SUPPORTED_VERSIONS;
193 6024 : ushort ext_supported_versions_ext_sz = 3;
194 6024 : uchar ext_supported_versions_sz = 2;
195 6024 : ushort ext_supported_versions[1] = { FD_TLS_VERSION_TLS13 };
196 :
197 6024 : ushort ext_key_share_ext_type = FD_TLS_EXT_KEY_SHARE;
198 6024 : ushort ext_key_share_ext_sz = 38;
199 6024 : ushort ext_key_share_sz1 = 36;
200 6024 : ushort ext_key_share_group = FD_TLS_GROUP_X25519;
201 6024 : ushort ext_key_share_sz = 32;
202 :
203 6024 : ushort ext_supported_groups_ext_type = FD_TLS_EXT_SUPPORTED_GROUPS;
204 6024 : ushort ext_supported_groups_ext_sz = 4;
205 6024 : ushort ext_supported_groups_sz = 2;
206 6024 : ushort ext_supported_groups[1] = { FD_TLS_GROUP_X25519 };
207 :
208 6024 : ushort ext_sigalg_ext_type = FD_TLS_EXT_SIGNATURE_ALGORITHMS;
209 6024 : ushort ext_sigalg_ext_sz = 4;
210 6024 : ushort ext_sigalg_sz = 2;
211 6024 : ushort ext_sigalg[1] = { FD_TLS_SIGNATURE_ED25519 };
212 :
213 6024 : # define FIELDS( FIELD ) \
214 12048 : FIELD( 0, &ext_supported_versions_ext_type, ushort, 1 ) \
215 12048 : FIELD( 1, &ext_supported_versions_ext_sz, ushort, 1 ) \
216 12048 : FIELD( 2, &ext_supported_versions_sz, uchar, 1 ) \
217 12048 : FIELD( 3, ext_supported_versions, ushort, 1 ) \
218 12048 : FIELD( 4, &ext_key_share_ext_type, ushort, 1 ) \
219 12048 : FIELD( 5, &ext_key_share_ext_sz, ushort, 1 ) \
220 12048 : FIELD( 6, &ext_key_share_sz1, ushort, 1 ) \
221 12048 : FIELD( 7, &ext_key_share_group, ushort, 1 ) \
222 12048 : FIELD( 8, &ext_key_share_sz, ushort, 1 ) \
223 12048 : FIELD( 9, &in->key_share.x25519[0], uchar, 32UL ) \
224 12048 : FIELD(10, &ext_supported_groups_ext_type, ushort, 1 ) \
225 12048 : FIELD(11, &ext_supported_groups_ext_sz, ushort, 1 ) \
226 12048 : FIELD(12, &ext_supported_groups_sz, ushort, 1 ) \
227 12048 : FIELD(13, ext_supported_groups, ushort, 1 ) \
228 12048 : FIELD(14, &ext_sigalg_ext_type, ushort, 1 ) \
229 12048 : FIELD(15, &ext_sigalg_ext_sz, ushort, 1 ) \
230 12048 : FIELD(16, &ext_sigalg_sz, ushort, 1 ) \
231 12048 : FIELD(17, ext_sigalg, ushort, 1 )
232 12048 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
233 6024 : # undef FIELDS
234 :
235 : /* Add ALPN */
236 :
237 6024 : if( in->alpn.bufsz ) {
238 6018 : fd_tls_ext_hdr_t ext_hdr = { .type = FD_TLS_EXT_ALPN,
239 6018 : .sz = (ushort)( in->alpn.bufsz+2 ) };
240 6018 : FD_TLS_ENCODE_SUB( fd_tls_encode_ext_hdr, &ext_hdr );
241 6018 : FD_TLS_ENCODE_SUB( fd_tls_encode_ext_alpn, &in->alpn );
242 6018 : }
243 :
244 : /* Add QUIC transport params */
245 :
246 6024 : if( in->quic_tp.buf ) {
247 6018 : ushort quic_tp_ext_type = FD_TLS_EXT_QUIC_TRANSPORT_PARAMS;
248 6018 : ushort quic_tp_ext_sz = (ushort)in->quic_tp.bufsz;
249 6018 : # define FIELDS( FIELD ) \
250 12036 : FIELD( 0, &quic_tp_ext_type, ushort, 1 ); \
251 12036 : FIELD( 1, &quic_tp_ext_sz, ushort, 1 ); \
252 12036 : FIELD( 2, in->quic_tp.buf, uchar, in->quic_tp.bufsz );
253 12036 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
254 6018 : # undef FIELDS
255 6018 : }
256 :
257 6024 : *extension_tot_sz = fd_ushort_bswap( (ushort)( (ulong)wire_laddr - extension_start ) );
258 6024 : return (long)( wire_laddr - (ulong)wire );
259 6024 : }
260 :
261 : long
262 : fd_tls_decode_server_hello( fd_tls_server_hello_t * out,
263 : uchar const * wire,
264 6027 : ulong wire_sz ) {
265 :
266 6027 : ulong wire_laddr = (ulong)wire;
267 :
268 : /* Decode static sized part of server hello */
269 :
270 6027 : ushort legacy_version; /* ==FD_TLS_VERSION_TLS12 */
271 6027 : uchar legacy_session_id_sz; /* ==0 */
272 6027 : ushort cipher_suite; /* ==FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256 */
273 6027 : uchar legacy_compression_method; /* ==0 */
274 :
275 6027 : # define FIELDS( FIELD ) \
276 12054 : FIELD( 0, &legacy_version, ushort, 1 ) \
277 12054 : FIELD( 1, &out->random[0], uchar, 32UL ) \
278 12054 : FIELD( 2, &legacy_session_id_sz, uchar, 1 ) \
279 12054 : FIELD( 3, &cipher_suite, ushort, 1 ) \
280 12054 : FIELD( 4, &legacy_compression_method, uchar, 1 )
281 12054 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
282 6027 : # undef FIELDS
283 :
284 6027 : if( FD_UNLIKELY( ( legacy_version != FD_TLS_VERSION_TLS12 )
285 6027 : | ( legacy_session_id_sz != 0 )
286 6027 : | ( legacy_compression_method != 0 ) ) )
287 0 : return -(long)FD_TLS_ALERT_PROTOCOL_VERSION;
288 :
289 6027 : if( FD_UNLIKELY( cipher_suite != FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256 ) )
290 3 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
291 :
292 : /* Reject HelloRetryRequest (we only support X25519) */
293 :
294 6024 : if( FD_UNLIKELY( 0==memcmp( out->random, hello_retry_magic, 32 ) ) )
295 0 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
296 :
297 : /* Read extensions */
298 :
299 24096 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
300 : /* Read extension type and length */
301 12048 : ushort ext_type;
302 12048 : ushort ext_sz;
303 12048 : # define FIELDS( FIELD ) \
304 24096 : FIELD( 0, &ext_type, ushort, 1 ) \
305 24096 : FIELD( 1, &ext_sz, ushort, 1 )
306 24096 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
307 12048 : # undef FIELDS
308 :
309 : /* Bounds check extension data */
310 12048 : if( FD_UNLIKELY( ext_sz > wire_sz ) )
311 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
312 :
313 12048 : ulong next_field = wire_laddr + ext_sz;
314 12048 : ulong next_sz = wire_sz - ext_sz;
315 :
316 : /* Decode extension data */
317 12048 : uchar const * ext_data = (uchar const *)wire_laddr;
318 12048 : long ext_parse_res;
319 12048 : switch( ext_type ) {
320 6024 : case FD_TLS_EXT_SUPPORTED_VERSIONS: {
321 6024 : ushort chosen_version;
322 6024 : FD_TLS_DECODE_FIELD( &chosen_version, ushort );
323 6024 : ext_parse_res = 2L;
324 6024 : if( FD_UNLIKELY( chosen_version!=FD_TLS_VERSION_TLS13 ) )
325 0 : return -(long)FD_TLS_ALERT_PROTOCOL_VERSION;
326 6024 : break;
327 6024 : }
328 6024 : case FD_TLS_EXT_KEY_SHARE:
329 6024 : ext_parse_res = fd_tls_decode_key_share( &out->key_share, ext_data, ext_sz );
330 6024 : break;
331 0 : case FD_TLS_EXT_QUIC_TRANSPORT_PARAMS:
332 : /* Copy transport params as-is (TODO...) */
333 0 : ext_parse_res = (long)ext_sz;
334 0 : break;
335 0 : default:
336 : /* Reject unsolicited extensions */
337 0 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
338 12048 : }
339 :
340 12048 : if( FD_UNLIKELY( ext_parse_res<0L ) )
341 0 : return ext_parse_res;
342 12048 : if( FD_UNLIKELY( ext_parse_res != (long)ext_sz ) )
343 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
344 :
345 12048 : wire_laddr = next_field;
346 12048 : wire_sz = next_sz;
347 12048 : }
348 6024 : FD_TLS_DECODE_LIST_END
349 :
350 : /* Check for required extensions */
351 :
352 6024 : if( FD_UNLIKELY( !out->key_share.has_x25519 ) )
353 0 : return -(long)FD_TLS_ALERT_MISSING_EXTENSION;
354 :
355 6024 : return (long)( wire_laddr - (ulong)wire );
356 6024 : }
357 :
358 : long
359 : fd_tls_encode_server_hello( fd_tls_server_hello_t const * in,
360 : uchar * wire,
361 6024 : ulong wire_sz ) {
362 :
363 6024 : ulong wire_laddr = (ulong)wire;
364 :
365 : /* Encode static sized part of server hello.
366 : (Assuming that session ID field is of a certain size) */
367 :
368 6024 : ushort legacy_version = FD_TLS_VERSION_TLS12;
369 6024 : uchar legacy_session_id_sz = (uchar)in->session_id.bufsz;
370 6024 : ushort cipher_suite = FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256;
371 6024 : uchar legacy_compression_method = 0;
372 :
373 6024 : # define FIELDS( FIELD ) \
374 12048 : FIELD( 0, &legacy_version, ushort, 1 ) \
375 12048 : FIELD( 1, &in->random[0], uchar, 32UL ) \
376 12048 : FIELD( 2, &legacy_session_id_sz, uchar, 1 ) \
377 12048 : FIELD( 3, in->session_id.buf, uchar, legacy_session_id_sz ) \
378 12048 : FIELD( 4, &cipher_suite, ushort, 1 ) \
379 12048 : FIELD( 5, &legacy_compression_method, uchar, 1 )
380 12048 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
381 6024 : # undef FIELDS
382 :
383 : /* Encode extensions */
384 :
385 6024 : ushort * extension_tot_sz = FD_TLS_SKIP_FIELD( ushort );
386 0 : ulong extension_start = wire_laddr;
387 :
388 6024 : ushort ext_supported_versions_ext_type = FD_TLS_EXT_SUPPORTED_VERSIONS;
389 6024 : ushort ext_supported_versions[1] = { FD_TLS_VERSION_TLS13 };
390 6024 : ushort ext_supported_versions_ext_sz = sizeof(ext_supported_versions);
391 :
392 6024 : ushort ext_key_share_ext_type = FD_TLS_EXT_KEY_SHARE;
393 6024 : ushort ext_key_share_ext_sz = sizeof(ushort) + sizeof(ushort) + 32UL;
394 6024 : ushort ext_key_share_group = FD_TLS_GROUP_X25519;
395 6024 : ushort ext_key_share_sz = 32UL;
396 :
397 6024 : # define FIELDS( FIELD ) \
398 12048 : FIELD( 0, &ext_supported_versions_ext_type, ushort, 1 ) \
399 12048 : FIELD( 1, &ext_supported_versions_ext_sz, ushort, 1 ) \
400 12048 : FIELD( 2, ext_supported_versions, ushort, 1 ) \
401 12048 : FIELD( 3, &ext_key_share_ext_type, ushort, 1 ) \
402 12048 : FIELD( 4, &ext_key_share_ext_sz, ushort, 1 ) \
403 12048 : FIELD( 5, &ext_key_share_group, ushort, 1 ) \
404 12048 : FIELD( 6, &ext_key_share_sz, ushort, 1 ) \
405 12048 : FIELD( 7, &in->key_share.x25519[0], uchar, 32UL )
406 12048 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
407 6024 : # undef FIELDS
408 :
409 6024 : *extension_tot_sz = fd_ushort_bswap( (ushort)( (ulong)wire_laddr - extension_start ) );
410 6024 : return (long)( wire_laddr - (ulong)wire );
411 6024 : }
412 :
413 : long
414 : fd_tls_encode_hello_retry_request( fd_tls_server_hello_t const * in,
415 : uchar * wire,
416 0 : ulong wire_sz ) {
417 :
418 0 : ulong wire_laddr = (ulong)wire;
419 :
420 0 : ushort legacy_version = FD_TLS_VERSION_TLS12;
421 0 : uchar legacy_session_id_sz = (uchar)in->session_id.bufsz;
422 0 : ushort cipher_suite = FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256;
423 0 : uchar legacy_compression_method = 0;
424 :
425 0 : # define FIELDS( FIELD ) \
426 0 : FIELD( 0, &legacy_version, ushort, 1 ) \
427 0 : FIELD( 1, hello_retry_magic, uchar, 32UL ) \
428 0 : FIELD( 2, &legacy_session_id_sz, uchar, 1 ) \
429 0 : FIELD( 3, in->session_id.buf, uchar, legacy_session_id_sz ) \
430 0 : FIELD( 4, &cipher_suite, ushort, 1 ) \
431 0 : FIELD( 5, &legacy_compression_method, uchar, 1 )
432 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
433 0 : # undef FIELDS
434 :
435 : /* Encode extensions */
436 :
437 0 : ushort * extension_tot_sz = FD_TLS_SKIP_FIELD( ushort );
438 0 : ulong extension_start = wire_laddr;
439 :
440 0 : ushort ext_supported_versions_ext_type = FD_TLS_EXT_SUPPORTED_VERSIONS;
441 0 : ushort ext_supported_versions[1] = { FD_TLS_VERSION_TLS13 };
442 0 : ushort ext_supported_versions_ext_sz = sizeof(ext_supported_versions);
443 :
444 0 : ushort ext_key_share_ext_type = FD_TLS_EXT_KEY_SHARE;
445 0 : ushort ext_key_share_ext_sz = sizeof(ushort);
446 0 : ushort ext_key_share_group = FD_TLS_GROUP_X25519;
447 :
448 0 : # define FIELDS( FIELD ) \
449 0 : FIELD( 0, &ext_supported_versions_ext_type, ushort, 1 ) \
450 0 : FIELD( 1, &ext_supported_versions_ext_sz, ushort, 1 ) \
451 0 : FIELD( 2, ext_supported_versions, ushort, 1 ) \
452 0 : FIELD( 3, &ext_key_share_ext_type, ushort, 1 ) \
453 0 : FIELD( 4, &ext_key_share_ext_sz, ushort, 1 ) \
454 0 : FIELD( 5, &ext_key_share_group, ushort, 1 )
455 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
456 0 : # undef FIELDS
457 :
458 0 : *extension_tot_sz = fd_ushort_bswap( (ushort)( (ulong)wire_laddr - extension_start ) );
459 0 : return (long)( wire_laddr - (ulong)wire );
460 0 : }
461 :
462 : long
463 : fd_tls_decode_enc_ext( fd_tls_enc_ext_t * const out,
464 : uchar const * const wire,
465 6021 : ulong wire_sz ) {
466 :
467 6021 : ulong wire_laddr = (ulong)wire;
468 :
469 24084 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
470 12036 : ushort ext_type;
471 12036 : ushort ext_sz;
472 12036 : # define FIELDS( FIELD ) \
473 24072 : FIELD( 0, &ext_type, ushort, 1 ) \
474 24072 : FIELD( 1, &ext_sz, ushort, 1 )
475 24072 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
476 12036 : # undef FIELDS
477 :
478 : /* Bounds check extension data
479 : (list_stop declared by DECODE_LIST macro) */
480 12036 : if( FD_UNLIKELY( wire_laddr + ext_sz > list_stop ) )
481 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
482 :
483 12036 : switch( ext_type ) {
484 6018 : case FD_TLS_EXT_ALPN: {
485 6018 : long res = fd_tls_decode_ext_alpn( &out->alpn, (uchar const *)wire_laddr, ext_sz );
486 6018 : if( FD_UNLIKELY( res<0L ) )
487 0 : return res;
488 6018 : if( FD_UNLIKELY( res!=(long)ext_sz ) )
489 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
490 6018 : break;
491 6018 : }
492 6018 : case FD_TLS_EXT_QUIC_TRANSPORT_PARAMS:
493 6018 : if( FD_UNLIKELY( ext_sz > FD_TLS_EXT_QUIC_PARAMS_SZ_MAX ) )
494 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
495 6018 : out->quic_tp.buf = (void *)wire_laddr;
496 6018 : out->quic_tp.bufsz = (ushort)ext_sz;
497 6018 : break;
498 0 : case FD_TLS_EXT_SERVER_CERT_TYPE:
499 0 : if( FD_UNLIKELY( (ext_sz>wire_sz) | (ext_sz!=1) ) )
500 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
501 0 : out->server_cert.cert_type = *(uchar const *)wire_laddr;
502 0 : break;
503 0 : case FD_TLS_EXT_CLIENT_CERT_TYPE:
504 0 : if( FD_UNLIKELY( (ext_sz>wire_sz) | (ext_sz!=1) ) )
505 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
506 0 : out->client_cert.cert_type = *(uchar const *)wire_laddr;
507 0 : break;
508 0 : default:
509 0 : break; /* TODO should we error on unknown extensions? */
510 12036 : }
511 :
512 12036 : wire_laddr += ext_sz;
513 12036 : wire_sz -= ext_sz;
514 12036 : }
515 6021 : FD_TLS_DECODE_LIST_END
516 :
517 : /* TODO Fail if trailing bytes detected? */
518 :
519 6021 : return (long)( wire_laddr - (ulong)wire );
520 6021 : }
521 :
522 : long
523 : fd_tls_encode_cert_x509( uchar const * x509,
524 : ulong x509_sz,
525 : uchar * wire,
526 6021 : ulong wire_sz ) {
527 :
528 6021 : ulong wire_laddr = (ulong)wire;
529 :
530 : /* TLS Record Header */
531 6021 : uchar msg_type = (uchar)FD_TLS_MSG_CERT;
532 :
533 : /* TLS Certificate Message header preceding X.509 data */
534 :
535 : /* All size prefixes known in advance */
536 6021 : fd_tls_u24_t msg_sz = fd_uint_to_tls_u24( (uint)( x509_sz + 9UL ) );
537 6021 : fd_tls_u24_t cert_list_sz = fd_uint_to_tls_u24( (uint)( x509_sz + 5UL ) );
538 6021 : fd_tls_u24_t cert_sz = fd_uint_to_tls_u24( (uint)( x509_sz ) );
539 :
540 : /* zero sz certificate_request_context
541 : (Server certificate never has a request context) */
542 6021 : uchar certificate_request_context_sz = (uchar)0;
543 :
544 : /* No certificate extensions */
545 6021 : ushort ext_sz = (ushort)0;
546 :
547 6021 : # define FIELDS( FIELD ) \
548 12042 : FIELD( 0, &msg_type, uchar, 1 ) \
549 12042 : FIELD( 1, &msg_sz, tls_u24, 1 ) \
550 12042 : FIELD( 2, &certificate_request_context_sz, uchar, 1 ) \
551 12042 : FIELD( 3, &cert_list_sz, tls_u24, 1 ) \
552 12042 : FIELD( 4, &cert_sz, tls_u24, 1 ) \
553 12042 : FIELD( 5, x509, uchar, x509_sz ) \
554 12042 : FIELD( 6, &ext_sz, ushort, 1 )
555 12042 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
556 6021 : # undef FIELDS
557 :
558 6021 : return (long)( wire_laddr - (ulong)wire );
559 6021 : }
560 :
561 : long
562 : fd_tls_encode_enc_ext( fd_tls_enc_ext_t const * in,
563 : uchar * wire,
564 6021 : ulong wire_sz ) {
565 :
566 6021 : ulong wire_laddr = (ulong)wire;
567 :
568 : /* ALPN */
569 :
570 6021 : if( in->alpn.bufsz ) {
571 6018 : fd_tls_ext_hdr_t ext_hdr = { .type = FD_TLS_EXT_ALPN,
572 6018 : .sz = (ushort)( in->alpn.bufsz+2 ) };
573 6018 : FD_TLS_ENCODE_SUB( fd_tls_encode_ext_hdr, &ext_hdr );
574 6018 : FD_TLS_ENCODE_SUB( fd_tls_encode_ext_alpn, &in->alpn );
575 6018 : }
576 :
577 : /* QUIC transport params */
578 :
579 6021 : if( in->quic_tp.buf ) {
580 6018 : ushort ext_type = FD_TLS_EXT_QUIC_TRANSPORT_PARAMS;
581 6018 : ushort ext_sz = (ushort)in->quic_tp.bufsz;
582 6018 : # define FIELDS( FIELD ) \
583 12036 : FIELD( 0, &ext_type, ushort, 1 ) \
584 12036 : FIELD( 1, &ext_sz, ushort, 1 ) \
585 12036 : FIELD( 2, in->quic_tp.buf, uchar, in->quic_tp.bufsz )
586 12036 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
587 6018 : # undef FIELDS
588 6018 : }
589 :
590 : /* Server certificate type */
591 :
592 6021 : if( in->server_cert.cert_type ) {
593 0 : ushort ext_type = FD_TLS_EXT_SERVER_CERT_TYPE;
594 0 : ushort ext_sz = 1;
595 0 : uchar cert_type = (uchar)in->server_cert.cert_type;
596 0 : # define FIELDS( FIELD ) \
597 0 : FIELD( 0, &ext_type, ushort, 1 ) \
598 0 : FIELD( 1, &ext_sz, ushort, 1 ) \
599 0 : FIELD( 2, &cert_type, uchar, 1 )
600 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
601 0 : # undef FIELDS
602 0 : }
603 :
604 : /* Client certificate type */
605 :
606 6021 : if( in->client_cert.cert_type ) {
607 0 : ushort ext_type = FD_TLS_EXT_CLIENT_CERT_TYPE;
608 0 : ushort ext_sz = 1;
609 0 : uchar cert_type = (uchar)in->client_cert.cert_type;
610 0 : # define FIELDS( FIELD ) \
611 0 : FIELD( 0, &ext_type, ushort, 1 ) \
612 0 : FIELD( 1, &ext_sz, ushort, 1 ) \
613 0 : FIELD( 2, &cert_type, uchar, 1 )
614 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
615 0 : # undef FIELDS
616 0 : }
617 :
618 6021 : return (long)( wire_laddr - (ulong)wire );
619 6021 : }
620 :
621 : long
622 : fd_tls_encode_raw_public_key( uchar const * key,
623 : uchar * wire,
624 0 : ulong wire_sz ) {
625 :
626 0 : ulong wire_laddr = (ulong)wire;
627 :
628 : /* TLS Record Header */
629 0 : uchar msg_type = (uchar)FD_TLS_MSG_CERT;
630 :
631 : /* TLS Certificate Message header preceding X.509 data */
632 :
633 : /* All size prefixes known in advance */
634 0 : uint rpk_sz = sizeof(fd_asn1_ed25519_pubkey_prefix)+32UL;
635 0 : fd_tls_u24_t msg_sz = fd_uint_to_tls_u24( (uint)( rpk_sz + 9UL ) );
636 0 : fd_tls_u24_t cert_list_sz = fd_uint_to_tls_u24( (uint)( rpk_sz + 5UL ) );
637 0 : fd_tls_u24_t cert_sz = fd_uint_to_tls_u24( (uint)( rpk_sz ) );
638 :
639 : /* zero sz certificate_request_context
640 : (Server certificate never has a request context) */
641 0 : uchar certificate_request_context_sz = (uchar)0;
642 :
643 : /* No certificate extensions */
644 0 : ushort ext_sz = (ushort)0;
645 :
646 0 : # define FIELDS( FIELD ) \
647 0 : FIELD( 0, &msg_type, uchar, 1 ) \
648 0 : FIELD( 1, &msg_sz, tls_u24, 1 ) \
649 0 : FIELD( 2, &certificate_request_context_sz, uchar, 1 ) \
650 0 : FIELD( 3, &cert_list_sz, tls_u24, 1 ) \
651 0 : FIELD( 4, &cert_sz, tls_u24, 1 ) \
652 0 : FIELD( 5, fd_asn1_ed25519_pubkey_prefix, uchar, sizeof(fd_asn1_ed25519_pubkey_prefix) ) \
653 0 : FIELD( 6, key, uchar, 32UL ) \
654 0 : FIELD( 7, &ext_sz, ushort, 1 )
655 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
656 0 : # undef FIELDS
657 :
658 0 : return (long)( wire_laddr - (ulong)wire );
659 0 : }
660 :
661 : long
662 : fd_tls_decode_cert_verify( fd_tls_cert_verify_t * out,
663 : uchar const * wire,
664 6021 : ulong wire_sz ) {
665 :
666 6021 : ulong wire_laddr = (ulong)wire;
667 :
668 6021 : ushort sig_sz;
669 6021 : # define FIELDS( FIELD ) \
670 12042 : FIELD( 0, &out->sig_alg, ushort, 1 ) \
671 12042 : FIELD( 1, &sig_sz, ushort, 1 ) \
672 12042 : FIELD( 2, out->sig, uchar, 64 )
673 12042 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
674 6021 : # undef FIELDS
675 :
676 6021 : if( FD_UNLIKELY( ( out->sig_alg != FD_TLS_SIGNATURE_ED25519 )
677 6021 : | ( sig_sz != 0x40UL ) ) )
678 0 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
679 :
680 6021 : return (long)( wire_laddr - (ulong)wire );
681 6021 : }
682 :
683 : long
684 : fd_tls_encode_cert_verify( fd_tls_cert_verify_t const * in,
685 : uchar * wire,
686 6021 : ulong wire_sz ) {
687 :
688 6021 : ulong wire_laddr = (ulong)wire;
689 :
690 6021 : ushort sig_sz = 0x40;
691 6021 : # define FIELDS( FIELD ) \
692 12042 : FIELD( 0, &in->sig_alg, ushort, 1 ) \
693 12042 : FIELD( 1, &sig_sz, ushort, 1 ) \
694 12042 : FIELD( 2, in->sig, uchar, 64 )
695 12042 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
696 6021 : # undef FIELDS
697 :
698 6021 : return (long)( wire_laddr - (ulong)wire );
699 6021 : }
700 :
701 : long
702 : fd_tls_decode_ext_server_name( fd_tls_ext_server_name_t * out,
703 : uchar const * wire,
704 3 : ulong wire_sz ) {
705 :
706 3 : ulong wire_laddr = (ulong)wire;
707 :
708 : /* TLS v1.3 server name lists practically always have one element. */
709 :
710 12 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
711 : /* Read type and length */
712 3 : uchar name_type;
713 3 : ushort name_sz;
714 3 : # define FIELDS( FIELD ) \
715 6 : FIELD( 0, &name_type, uchar, 1 ) \
716 6 : FIELD( 1, &name_sz, ushort, 1 )
717 6 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
718 3 : # undef FIELDS
719 :
720 : /* Bounds check name */
721 3 : if( FD_UNLIKELY( wire_laddr + name_sz > list_stop ) )
722 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
723 :
724 : /* Decode name on first use */
725 3 : if( ( ( name_type == FD_TLS_SERVER_NAME_TYPE_DNS )
726 3 : & ( name_sz < 254 )
727 3 : & ( out->host_name_len == 0 ) ) ) {
728 3 : out->host_name_len = (uchar)name_sz;
729 3 : memcpy( out->host_name, (uchar const *)wire_laddr, name_sz );
730 3 : out->host_name[ name_sz ] = '\0';
731 3 : }
732 :
733 : /* Seek to next name */
734 3 : wire_laddr += name_sz;
735 3 : wire_sz -= name_sz;
736 3 : }
737 3 : FD_TLS_DECODE_LIST_END
738 :
739 3 : return (long)( wire_laddr - (ulong)wire );
740 3 : }
741 :
742 : long
743 : fd_tls_decode_ext_supported_groups( fd_tls_ext_supported_groups_t * out,
744 : uchar const * wire,
745 6027 : ulong wire_sz ) {
746 :
747 6027 : ulong wire_laddr = (ulong)wire;
748 :
749 24108 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
750 6033 : ushort group;
751 6033 : FD_TLS_DECODE_FIELD( &group, ushort );
752 6033 : switch( group ) {
753 6027 : case FD_TLS_GROUP_X25519:
754 6027 : out->x25519 = 1;
755 6027 : break;
756 6 : default:
757 : /* Ignore unsupported groups ... */
758 6 : break;
759 6033 : }
760 6033 : }
761 6027 : FD_TLS_DECODE_LIST_END
762 :
763 6027 : return (long)( wire_laddr - (ulong)wire );
764 6027 : }
765 :
766 : long
767 : fd_tls_decode_ext_supported_versions( fd_tls_ext_supported_versions_t * out,
768 : uchar const * wire,
769 6027 : ulong wire_sz ) {
770 :
771 6027 : ulong wire_laddr = (ulong)wire;
772 :
773 24108 : FD_TLS_DECODE_LIST_BEGIN( uchar, alignof(ushort) ) {
774 6027 : ushort group;
775 6027 : FD_TLS_DECODE_FIELD( &group, ushort );
776 6027 : switch( group ) {
777 6027 : case FD_TLS_VERSION_TLS13:
778 6027 : out->tls13 = 1;
779 6027 : break;
780 0 : default:
781 : /* Ignore unsupported TLS versions ... */
782 0 : break;
783 6027 : }
784 6027 : }
785 6027 : FD_TLS_DECODE_LIST_END
786 :
787 6027 : return (long)( wire_laddr - (ulong)wire );
788 6027 : }
789 :
790 : long
791 : fd_tls_decode_ext_signature_algorithms( fd_tls_ext_signature_algorithms_t * out,
792 : uchar const * wire,
793 6027 : ulong wire_sz ) {
794 :
795 6027 : ulong wire_laddr = (ulong)wire;
796 :
797 24108 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(ushort) ) {
798 6051 : ushort group;
799 6051 : FD_TLS_DECODE_FIELD( &group, ushort );
800 6051 : switch( group ) {
801 6027 : case FD_TLS_SIGNATURE_ED25519:
802 6027 : out->ed25519 = 1;
803 6027 : break;
804 24 : default:
805 : /* Ignore unsupported signature algorithms ... */
806 24 : break;
807 6051 : }
808 6051 : }
809 6027 : FD_TLS_DECODE_LIST_END
810 :
811 6027 : return (long)( wire_laddr - (ulong)wire );
812 6027 : }
813 :
814 : long
815 : fd_tls_decode_key_share( fd_tls_key_share_t * out,
816 : uchar const * wire,
817 12051 : ulong wire_sz ) {
818 :
819 12051 : ulong wire_laddr = (ulong)wire;
820 :
821 : /* Read type and length */
822 12051 : ushort group;
823 12051 : ushort kex_data_sz;
824 12051 : # define FIELDS( FIELD ) \
825 24102 : FIELD( 0, &group, ushort, 1 ) \
826 24102 : FIELD( 1, &kex_data_sz, ushort, 1 )
827 24102 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
828 12051 : # undef FIELDS
829 :
830 : /* Bounds check */
831 12051 : if( FD_UNLIKELY( kex_data_sz > wire_sz ) )
832 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
833 :
834 12051 : switch( group ) {
835 12051 : case FD_TLS_GROUP_X25519:
836 12051 : if( FD_UNLIKELY( kex_data_sz != 32UL ) )
837 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
838 12051 : out->has_x25519 = 1;
839 12051 : memcpy( out->x25519, (uchar const *)wire_laddr, 32UL );
840 12051 : break;
841 0 : default:
842 : /* Ignore unsupported key share groups ... */
843 0 : break;
844 12051 : }
845 :
846 : /* Seek to next group */
847 12051 : wire_laddr += kex_data_sz;
848 12051 : wire_sz -= kex_data_sz;
849 :
850 12051 : return (long)( wire_laddr - (ulong)wire );
851 12051 : }
852 :
853 : long
854 : fd_tls_decode_key_share_list( fd_tls_key_share_t * out,
855 : uchar const * wire,
856 6027 : ulong wire_sz ) {
857 :
858 6027 : ulong wire_laddr = (ulong)wire;
859 :
860 24108 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
861 6027 : FD_TLS_DECODE_SUB( fd_tls_decode_key_share, out );
862 6027 : }
863 6027 : FD_TLS_DECODE_LIST_END
864 :
865 6027 : return (long)( wire_laddr - (ulong)wire );
866 6027 : }
867 :
868 : long
869 : fd_tls_decode_ext_cert_type_list( fd_tls_ext_cert_type_list_t * out,
870 : uchar const * wire,
871 6 : ulong wire_sz ) {
872 :
873 6 : ulong wire_laddr = (ulong)wire;
874 :
875 6 : out->present = 1;
876 24 : FD_TLS_DECODE_LIST_BEGIN( uchar, alignof(uchar) ) {
877 12 : uchar cert_type;
878 12 : FD_TLS_DECODE_FIELD( &cert_type, uchar ); /* is this really a uchar? */
879 12 : switch( cert_type ) {
880 6 : case FD_TLS_CERTTYPE_X509: out->x509 = 1; break;
881 6 : case FD_TLS_CERTTYPE_RAW_PUBKEY: out->raw_pubkey = 1; break;
882 0 : default:
883 : /* Ignore unsupported cert types ... */
884 0 : break;
885 12 : }
886 12 : }
887 6 : FD_TLS_DECODE_LIST_END
888 :
889 6 : return (long)( wire_laddr - (ulong)wire );
890 6 : }
891 :
892 : long
893 : fd_tls_encode_ext_cert_type_list( fd_tls_ext_cert_type_list_t in,
894 : uchar const * wire,
895 0 : ulong wire_sz ) {
896 :
897 0 : ulong wire_laddr = (ulong)wire;
898 :
899 : /* Encode list size */
900 0 : uchar cnt = (uchar)fd_uchar_popcnt( in.uc );
901 0 : FD_TLS_ENCODE_FIELD( &cnt, uchar );
902 :
903 : /* Encode list */
904 0 : uchar * fields = FD_TLS_SKIP_FIELDS( uchar, cnt );
905 0 : if( in.x509 ) *fields++ = FD_TLS_CERTTYPE_X509;
906 0 : if( in.raw_pubkey ) *fields++ = FD_TLS_CERTTYPE_RAW_PUBKEY;
907 :
908 0 : return (long)( wire_laddr - (ulong)wire );
909 0 : }
910 :
911 : long
912 : fd_tls_decode_ext_cert_type( fd_tls_ext_cert_type_t * out,
913 : uchar const * wire,
914 0 : ulong wire_sz ) {
915 0 : ulong wire_laddr = (ulong)wire;
916 0 : FD_TLS_DECODE_FIELD( &out->cert_type, uchar );
917 0 : return (long)( wire_laddr - (ulong)wire );
918 0 : }
919 :
920 : long
921 : fd_tls_encode_ext_cert_type( fd_tls_ext_cert_type_t in,
922 : uchar const * wire,
923 0 : ulong wire_sz ) {
924 0 : ulong wire_laddr = (ulong)wire;
925 0 : FD_TLS_ENCODE_FIELD( &in.cert_type, uchar );
926 0 : return (long)( wire_laddr - (ulong)wire );
927 0 : }
928 :
929 : long
930 : fd_tls_decode_ext_opaque( fd_tls_ext_opaque_t * const out,
931 : uchar const * const wire,
932 18066 : ulong wire_sz ) {
933 18066 : out->buf = wire;
934 18066 : out->bufsz = wire_sz;
935 18066 : return (long)wire_sz;
936 18066 : }
937 :
938 : long
939 : fd_tls_decode_ext_alpn( fd_tls_ext_alpn_t * const out,
940 : uchar const * const wire,
941 12042 : ulong wire_sz ) {
942 12042 : ulong wire_laddr = (ulong)wire;
943 12042 : ushort alpn_sz;
944 12042 : FD_TLS_DECODE_FIELD( &alpn_sz, ushort );
945 12042 : if( FD_UNLIKELY( (ulong)alpn_sz != wire_sz ) )
946 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
947 12042 : return 2L + (long)fd_tls_decode_ext_opaque( out, (uchar const *)wire_laddr, wire_sz );
948 12042 : }
949 :
950 : long
951 : fd_tls_encode_ext_alpn( fd_tls_ext_alpn_t const * in,
952 : uchar * wire,
953 12036 : ulong wire_sz ) {
954 12036 : ulong sz = 2UL + in->bufsz;
955 12036 : if( FD_UNLIKELY( sz>wire_sz ) )
956 0 : return -(long)FD_TLS_ALERT_INTERNAL_ERROR;
957 12036 : wire[0] = (uchar)( (in->bufsz >> 8)&0xFF );
958 12036 : wire[1] = (uchar)( in->bufsz &0xFF );
959 12036 : fd_memcpy( wire+2UL, in->buf, in->bufsz );
960 12036 : return (long)sz;
961 12036 : }
962 :
963 : /* fd_tls_client_handle_x509 extracts the Ed25519 subject public key
964 : from the certificate. Does not validate the signature found on the
965 : certificate (might be self-signed). [cert,cert+cert_sz) points to
966 : an ASN.1 DER serialization of the certificate. On success, copies
967 : public key bits to out_pubkey and returns 0U. On failure, returns
968 : positive TLS alert error code. */
969 :
970 : static uint
971 : fd_tls_client_handle_x509( uchar const * const cert,
972 : ulong const cert_sz,
973 6021 : uchar const ** const out_pubkey ) {
974 6021 : uchar const * pubkey = fd_x509_mock_pubkey( cert, cert_sz );
975 6021 : if( FD_UNLIKELY( !pubkey ) )
976 0 : return FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE;
977 6021 : *out_pubkey = pubkey;
978 6021 : return 0U;
979 6021 : }
980 :
981 : static long
982 : fd_tls_extract_cert_pubkey_( fd_tls_extract_cert_pubkey_res_t * res,
983 : uchar const * cert_chain,
984 : ulong cert_chain_sz,
985 6021 : uint cert_type ) {
986 :
987 6021 : fd_memset( res, 0, sizeof(fd_tls_extract_cert_pubkey_res_t) );
988 :
989 6021 : ulong wire_laddr = (ulong)cert_chain;
990 6021 : ulong wire_sz = cert_chain_sz;
991 :
992 : /* Skip 'opaque certificate_request_context<0..2^8-1>' */
993 6021 : uchar const * opaque_sz = FD_TLS_SKIP_FIELD( uchar );
994 6021 : uchar const * opaque = FD_TLS_SKIP_FIELDS( uchar, *opaque_sz );
995 0 : (void)opaque;
996 :
997 : /* Get first entry of certificate chain
998 : CertificateEntry certificate_list<0..2^24-1> */
999 6021 : fd_tls_u24_t const * cert_list_sz_be = FD_TLS_SKIP_FIELD( fd_tls_u24_t );
1000 0 : fd_tls_u24_t cert_list_sz_ = fd_tls_u24_bswap( *cert_list_sz_be );
1001 6021 : uint cert_list_sz = fd_tls_u24_to_uint( cert_list_sz_ );
1002 6021 : if( FD_UNLIKELY( cert_list_sz==0U ) ) {
1003 0 : res->alert = FD_TLS_ALERT_BAD_CERTIFICATE;
1004 0 : res->reason = FD_TLS_REASON_CERT_CHAIN_EMPTY;
1005 0 : return -1L;
1006 0 : }
1007 :
1008 : /* Get certificate size */
1009 6021 : fd_tls_u24_t const * cert_sz_be = FD_TLS_SKIP_FIELD( fd_tls_u24_t );
1010 0 : fd_tls_u24_t cert_sz_ = fd_tls_u24_bswap( *cert_sz_be );
1011 6021 : uint cert_sz = fd_tls_u24_to_uint( cert_sz_ );
1012 6021 : if( FD_UNLIKELY( cert_sz>wire_sz ) ) {
1013 0 : res->alert = FD_TLS_ALERT_DECODE_ERROR;
1014 0 : res->reason = FD_TLS_REASON_CERT_PARSE;
1015 0 : return -1L;
1016 0 : }
1017 :
1018 6021 : void * cert = (void *)wire_laddr;
1019 :
1020 6021 : switch( cert_type ) {
1021 :
1022 6021 : case FD_TLS_CERTTYPE_X509: {
1023 :
1024 : /* DER-encoded X.509 certificate */
1025 :
1026 6021 : uint x509_alert = fd_tls_client_handle_x509( cert, cert_sz, &res->pubkey );
1027 6021 : if( FD_UNLIKELY( x509_alert!=0U ) ) {
1028 0 : res->pubkey = NULL;
1029 0 : res->alert = x509_alert;
1030 0 : res->reason = FD_TLS_REASON_X509_PARSE;
1031 0 : return -1L;
1032 0 : }
1033 :
1034 6021 : return 0L;
1035 6021 : }
1036 :
1037 0 : case FD_TLS_CERTTYPE_RAW_PUBKEY: {
1038 :
1039 : /* Interpret certificate entry as raw public key (RFC 7250)
1040 : 'opaque ASN1_subjectPublicKeyInfo<1..2^24-1>' */
1041 :
1042 0 : res->pubkey = fd_ed25519_public_key_from_asn1( cert, cert_sz );
1043 0 : if( FD_UNLIKELY( !res->pubkey ) ) {
1044 0 : res->reason = FD_TLS_REASON_SPKI_PARSE;
1045 0 : res->alert = FD_TLS_ALERT_BAD_CERTIFICATE;
1046 0 : return -1L;
1047 0 : }
1048 :
1049 0 : return 0L;
1050 0 : }
1051 :
1052 0 : default:
1053 0 : __builtin_unreachable();
1054 :
1055 6021 : } /* end switch */
1056 6021 : }
1057 :
1058 : fd_tls_extract_cert_pubkey_res_t
1059 : fd_tls_extract_cert_pubkey( uchar const * cert_chain,
1060 : ulong cert_chain_sz,
1061 6021 : uint cert_type ) {
1062 6021 : fd_tls_extract_cert_pubkey_res_t res;
1063 6021 : long ret = fd_tls_extract_cert_pubkey_( &res, cert_chain, cert_chain_sz, cert_type );
1064 6021 : (void)ret;
1065 6021 : return res;
1066 6021 : }
|