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