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 0 : ulong wire_sz ) {
38 :
39 0 : 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 0 : ushort legacy_version; /* ==FD_TLS_VERSION_TLS12 */
45 0 : uchar legacy_session_id_sz; /* ==0 */
46 :
47 0 : # define FIELDS( FIELD ) \
48 0 : FIELD( 0, &legacy_version, ushort, 1 ) \
49 0 : FIELD( 1, &out->random[0], uchar, 32UL ) \
50 0 : FIELD( 2, &legacy_session_id_sz, uchar, 1 )
51 0 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
52 0 : # undef FIELDS
53 :
54 0 : if( FD_UNLIKELY( ( legacy_session_id_sz > 32 ) |
55 0 : ( wire_sz < legacy_session_id_sz ) ) )
56 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
57 :
58 0 : out->session_id.buf = (void *)wire_laddr;
59 0 : out->session_id.bufsz = legacy_session_id_sz;
60 0 : wire_laddr += legacy_session_id_sz;
61 0 : wire_sz -= legacy_session_id_sz;
62 :
63 : /* Decode cipher suite list */
64 :
65 0 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(ushort) ) {
66 0 : ushort cipher_suite;
67 0 : FD_TLS_DECODE_FIELD( &cipher_suite, ushort );
68 :
69 0 : switch( cipher_suite ) {
70 0 : case FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256:
71 0 : out->cipher_suites.aes_128_gcm_sha256 = 1;
72 0 : break;
73 0 : default:
74 : /* Ignore unsupported cipher suites ... */
75 0 : break;
76 0 : }
77 0 : }
78 0 : FD_TLS_DECODE_LIST_END
79 :
80 : /* Decode next static sized part of client hello */
81 :
82 0 : uchar legacy_compression_method_cnt; /* == 1 */
83 0 : uchar legacy_compression_methods[ 1 ]; /* =={0} */
84 :
85 0 : # define FIELDS( FIELD ) \
86 0 : FIELD( 5, &legacy_compression_method_cnt, uchar, 1 ) \
87 0 : FIELD( 6, &legacy_compression_methods[0], uchar, 1 )
88 0 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
89 0 : # undef FIELDS
90 :
91 0 : if( FD_UNLIKELY( ( legacy_compression_method_cnt != 1 )
92 0 : | ( legacy_compression_methods[0] != 0 ) ) )
93 0 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
94 :
95 : /* Read extensions */
96 :
97 0 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
98 : /* Read extension type and length */
99 0 : ushort ext_type;
100 0 : ushort ext_sz;
101 0 : # define FIELDS( FIELD ) \
102 0 : FIELD( 0, &ext_type, ushort, 1 ) \
103 0 : FIELD( 1, &ext_sz, ushort, 1 )
104 0 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
105 0 : # undef FIELDS
106 :
107 : /* Bounds check extension data */
108 0 : if( FD_UNLIKELY( ext_sz > wire_sz ) )
109 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
110 :
111 : /* Decode extension data */
112 0 : uchar const * ext_data = (uchar const *)wire_laddr;
113 0 : long ext_parse_res;
114 0 : switch( ext_type ) {
115 0 : case FD_TLS_EXT_SUPPORTED_VERSIONS:
116 0 : ext_parse_res = fd_tls_decode_ext_supported_versions( &out->supported_versions, ext_data, ext_sz );
117 0 : break;
118 0 : case FD_TLS_EXT_SERVER_NAME:
119 0 : ext_parse_res = fd_tls_decode_ext_server_name( &out->server_name, ext_data, ext_sz );
120 0 : break;
121 0 : case FD_TLS_EXT_SUPPORTED_GROUPS:
122 0 : ext_parse_res = fd_tls_decode_ext_supported_groups( &out->supported_groups, ext_data, ext_sz );
123 0 : break;
124 0 : case FD_TLS_EXT_SIGNATURE_ALGORITHMS:
125 0 : ext_parse_res = fd_tls_decode_ext_signature_algorithms( &out->signature_algorithms, ext_data, ext_sz );
126 0 : break;
127 0 : case FD_TLS_EXT_KEY_SHARE:
128 0 : ext_parse_res = fd_tls_decode_key_share_list( &out->key_share, ext_data, ext_sz );
129 0 : break;
130 0 : case FD_TLS_EXT_SERVER_CERT_TYPE:
131 0 : ext_parse_res = fd_tls_decode_ext_cert_type_list( &out->server_cert_types, ext_data, ext_sz );
132 0 : break;
133 0 : case FD_TLS_EXT_CLIENT_CERT_TYPE:
134 0 : ext_parse_res = fd_tls_decode_ext_cert_type_list( &out->client_cert_types, ext_data, ext_sz );
135 0 : break;
136 0 : case FD_TLS_EXT_QUIC_TRANSPORT_PARAMS:
137 0 : ext_parse_res = fd_tls_decode_ext_quic_tp( &out->quic_tp, ext_data, ext_sz );
138 0 : break;
139 0 : case FD_TLS_EXT_ALPN:
140 0 : ext_parse_res = fd_tls_decode_ext_alpn( &out->alpn, ext_data, ext_sz );
141 0 : break;
142 0 : default:
143 0 : ext_parse_res = (long)ext_sz;
144 0 : break;
145 0 : }
146 0 : if( FD_UNLIKELY( ext_parse_res<0L ) )
147 0 : return ext_parse_res;
148 0 : 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 0 : wire_laddr += ext_sz;
153 0 : wire_sz -= ext_sz;
154 0 : }
155 0 : FD_TLS_DECODE_LIST_END
156 :
157 0 : return (long)( wire_laddr - (ulong)wire );
158 0 : }
159 :
160 : long
161 : fd_tls_encode_client_hello( fd_tls_client_hello_t const * in,
162 : uchar * wire,
163 0 : ulong wire_sz ) {
164 :
165 0 : ulong wire_laddr = (ulong)wire;
166 :
167 : /* Encode static sized part of client hello */
168 :
169 0 : ushort legacy_version = FD_TLS_VERSION_TLS12;
170 0 : uchar legacy_session_id_sz = 0;
171 0 : ushort cipher_suite_sz = 1*sizeof(ushort);
172 0 : ushort cipher_suites[1] = { FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256 };
173 0 : uchar legacy_comp_method_sz = 1;
174 0 : uchar legacy_comp_method[1] = {0};
175 :
176 0 : # define FIELDS( FIELD ) \
177 0 : FIELD( 0, &legacy_version, ushort, 1 ) \
178 0 : FIELD( 1, in->random, uchar, 32UL ) \
179 0 : FIELD( 2, &legacy_session_id_sz, uchar, 1 ) \
180 0 : FIELD( 3, &cipher_suite_sz, ushort, 1 ) \
181 0 : FIELD( 4, cipher_suites, ushort, 1 ) \
182 0 : FIELD( 5, &legacy_comp_method_sz, uchar, 1 ) \
183 0 : FIELD( 6, legacy_comp_method, uchar, 1 )
184 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
185 0 : # undef FIELDS
186 :
187 : /* Encode extensions */
188 :
189 0 : ushort * extension_tot_sz = FD_TLS_SKIP_FIELD( ushort );
190 0 : ulong extension_start = wire_laddr;
191 :
192 0 : ushort ext_supported_versions_ext_type = FD_TLS_EXT_SUPPORTED_VERSIONS;
193 0 : ushort ext_supported_versions_ext_sz = 3;
194 0 : uchar ext_supported_versions_sz = 2;
195 0 : ushort ext_supported_versions[1] = { FD_TLS_VERSION_TLS13 };
196 :
197 0 : ushort ext_key_share_ext_type = FD_TLS_EXT_KEY_SHARE;
198 0 : ushort ext_key_share_ext_sz = 38;
199 0 : ushort ext_key_share_sz1 = 36;
200 0 : ushort ext_key_share_group = FD_TLS_GROUP_X25519;
201 0 : ushort ext_key_share_sz = 32;
202 :
203 0 : ushort ext_supported_groups_ext_type = FD_TLS_EXT_SUPPORTED_GROUPS;
204 0 : ushort ext_supported_groups_ext_sz = 4;
205 0 : ushort ext_supported_groups_sz = 2;
206 0 : ushort ext_supported_groups[1] = { FD_TLS_GROUP_X25519 };
207 :
208 0 : ushort ext_sigalg_ext_type = FD_TLS_EXT_SIGNATURE_ALGORITHMS;
209 0 : ushort ext_sigalg_ext_sz = 4;
210 0 : ushort ext_sigalg_sz = 2;
211 0 : ushort ext_sigalg[1] = { FD_TLS_SIGNATURE_ED25519 };
212 :
213 0 : # define FIELDS( FIELD ) \
214 0 : FIELD( 0, &ext_supported_versions_ext_type, ushort, 1 ) \
215 0 : FIELD( 1, &ext_supported_versions_ext_sz, ushort, 1 ) \
216 0 : FIELD( 2, &ext_supported_versions_sz, uchar, 1 ) \
217 0 : FIELD( 3, ext_supported_versions, ushort, 1 ) \
218 0 : FIELD( 4, &ext_key_share_ext_type, ushort, 1 ) \
219 0 : FIELD( 5, &ext_key_share_ext_sz, ushort, 1 ) \
220 0 : FIELD( 6, &ext_key_share_sz1, ushort, 1 ) \
221 0 : FIELD( 7, &ext_key_share_group, ushort, 1 ) \
222 0 : FIELD( 8, &ext_key_share_sz, ushort, 1 ) \
223 0 : FIELD( 9, &in->key_share.x25519[0], uchar, 32UL ) \
224 0 : FIELD(10, &ext_supported_groups_ext_type, ushort, 1 ) \
225 0 : FIELD(11, &ext_supported_groups_ext_sz, ushort, 1 ) \
226 0 : FIELD(12, &ext_supported_groups_sz, ushort, 1 ) \
227 0 : FIELD(13, ext_supported_groups, ushort, 1 ) \
228 0 : FIELD(14, &ext_sigalg_ext_type, ushort, 1 ) \
229 0 : FIELD(15, &ext_sigalg_ext_sz, ushort, 1 ) \
230 0 : FIELD(16, &ext_sigalg_sz, ushort, 1 ) \
231 0 : FIELD(17, ext_sigalg, ushort, 1 )
232 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
233 0 : # undef FIELDS
234 :
235 : /* Add ALPN */
236 :
237 0 : if( in->alpn.bufsz ) {
238 0 : fd_tls_ext_hdr_t ext_hdr = { .type = FD_TLS_EXT_ALPN,
239 0 : .sz = (ushort)( in->alpn.bufsz+2 ) };
240 0 : FD_TLS_ENCODE_SUB( fd_tls_encode_ext_hdr, &ext_hdr );
241 0 : FD_TLS_ENCODE_SUB( fd_tls_encode_ext_alpn, &in->alpn );
242 0 : }
243 :
244 : /* Add QUIC transport params */
245 :
246 0 : if( in->quic_tp.buf ) {
247 0 : ushort quic_tp_ext_type = FD_TLS_EXT_QUIC_TRANSPORT_PARAMS;
248 0 : ushort quic_tp_ext_sz = (ushort)in->quic_tp.bufsz;
249 0 : # define FIELDS( FIELD ) \
250 0 : FIELD( 0, &quic_tp_ext_type, ushort, 1 ); \
251 0 : FIELD( 1, &quic_tp_ext_sz, ushort, 1 ); \
252 0 : FIELD( 2, in->quic_tp.buf, uchar, in->quic_tp.bufsz );
253 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
254 0 : # undef FIELDS
255 0 : }
256 :
257 0 : FD_STORE( ushort, extension_tot_sz, fd_ushort_bswap( (ushort)( (ulong)wire_laddr - extension_start ) ) );
258 0 : return (long)( wire_laddr - (ulong)wire );
259 0 : }
260 :
261 : long
262 : fd_tls_decode_server_hello( fd_tls_server_hello_t * out,
263 : uchar const * wire,
264 0 : ulong wire_sz ) {
265 :
266 0 : ulong wire_laddr = (ulong)wire;
267 :
268 : /* Decode static sized part of server hello */
269 :
270 0 : ushort legacy_version; /* ==FD_TLS_VERSION_TLS12 */
271 0 : uchar legacy_session_id_sz; /* ==0 */
272 0 : ushort cipher_suite; /* ==FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256 */
273 0 : uchar legacy_compression_method; /* ==0 */
274 :
275 0 : # define FIELDS( FIELD ) \
276 0 : FIELD( 0, &legacy_version, ushort, 1 ) \
277 0 : FIELD( 1, &out->random[0], uchar, 32UL ) \
278 0 : FIELD( 2, &legacy_session_id_sz, uchar, 1 ) \
279 0 : FIELD( 3, &cipher_suite, ushort, 1 ) \
280 0 : FIELD( 4, &legacy_compression_method, uchar, 1 )
281 0 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
282 0 : # undef FIELDS
283 :
284 0 : if( FD_UNLIKELY( ( legacy_version != FD_TLS_VERSION_TLS12 )
285 0 : | ( legacy_session_id_sz != 0 )
286 0 : | ( legacy_compression_method != 0 ) ) )
287 0 : return -(long)FD_TLS_ALERT_PROTOCOL_VERSION;
288 :
289 0 : if( FD_UNLIKELY( cipher_suite != FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256 ) )
290 0 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
291 :
292 : /* Reject HelloRetryRequest (we only support X25519) */
293 :
294 0 : 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 0 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
300 : /* Read extension type and length */
301 0 : ushort ext_type;
302 0 : ushort ext_sz;
303 0 : # define FIELDS( FIELD ) \
304 0 : FIELD( 0, &ext_type, ushort, 1 ) \
305 0 : FIELD( 1, &ext_sz, ushort, 1 )
306 0 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
307 0 : # undef FIELDS
308 :
309 : /* Bounds check extension data */
310 0 : if( FD_UNLIKELY( ext_sz > wire_sz ) )
311 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
312 :
313 0 : ulong next_field = wire_laddr + ext_sz;
314 0 : ulong next_sz = wire_sz - ext_sz;
315 :
316 : /* Decode extension data */
317 0 : uchar const * ext_data = (uchar const *)wire_laddr;
318 0 : long ext_parse_res;
319 0 : switch( ext_type ) {
320 0 : case FD_TLS_EXT_SUPPORTED_VERSIONS: {
321 0 : ushort chosen_version;
322 0 : FD_TLS_DECODE_FIELD( &chosen_version, ushort );
323 0 : ext_parse_res = 2L;
324 0 : if( FD_UNLIKELY( chosen_version!=FD_TLS_VERSION_TLS13 ) )
325 0 : return -(long)FD_TLS_ALERT_PROTOCOL_VERSION;
326 0 : break;
327 0 : }
328 0 : case FD_TLS_EXT_KEY_SHARE:
329 0 : ext_parse_res = fd_tls_decode_key_share( &out->key_share, ext_data, ext_sz );
330 0 : 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 0 : }
339 :
340 0 : if( FD_UNLIKELY( ext_parse_res<0L ) )
341 0 : return ext_parse_res;
342 0 : if( FD_UNLIKELY( ext_parse_res != (long)ext_sz ) )
343 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
344 :
345 0 : wire_laddr = next_field;
346 0 : wire_sz = next_sz;
347 0 : }
348 0 : FD_TLS_DECODE_LIST_END
349 :
350 : /* Check for required extensions */
351 :
352 0 : if( FD_UNLIKELY( !out->key_share.has_x25519 ) )
353 0 : return -(long)FD_TLS_ALERT_MISSING_EXTENSION;
354 :
355 0 : return (long)( wire_laddr - (ulong)wire );
356 0 : }
357 :
358 : long
359 : fd_tls_encode_server_hello( fd_tls_server_hello_t const * in,
360 : uchar * wire,
361 0 : ulong wire_sz ) {
362 :
363 0 : 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 0 : ushort legacy_version = FD_TLS_VERSION_TLS12;
369 0 : uchar legacy_session_id_sz = (uchar)in->session_id.bufsz;
370 0 : ushort cipher_suite = FD_TLS_CIPHER_SUITE_AES_128_GCM_SHA256;
371 0 : uchar legacy_compression_method = 0;
372 :
373 0 : # define FIELDS( FIELD ) \
374 0 : FIELD( 0, &legacy_version, ushort, 1 ) \
375 0 : FIELD( 1, &in->random[0], uchar, 32UL ) \
376 0 : FIELD( 2, &legacy_session_id_sz, uchar, 1 ) \
377 0 : FIELD( 3, in->session_id.buf, uchar, legacy_session_id_sz ) \
378 0 : FIELD( 4, &cipher_suite, ushort, 1 ) \
379 0 : FIELD( 5, &legacy_compression_method, uchar, 1 )
380 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
381 0 : # undef FIELDS
382 :
383 : /* Encode extensions */
384 :
385 0 : ushort * extension_tot_sz = FD_TLS_SKIP_FIELD( ushort );
386 0 : ulong extension_start = wire_laddr;
387 :
388 0 : ushort ext_supported_versions_ext_type = FD_TLS_EXT_SUPPORTED_VERSIONS;
389 0 : ushort ext_supported_versions[1] = { FD_TLS_VERSION_TLS13 };
390 0 : ushort ext_supported_versions_ext_sz = sizeof(ext_supported_versions);
391 :
392 0 : ushort ext_key_share_ext_type = FD_TLS_EXT_KEY_SHARE;
393 0 : ushort ext_key_share_ext_sz = sizeof(ushort) + sizeof(ushort) + 32UL;
394 0 : ushort ext_key_share_group = FD_TLS_GROUP_X25519;
395 0 : ushort ext_key_share_sz = 32UL;
396 :
397 0 : # define FIELDS( FIELD ) \
398 0 : FIELD( 0, &ext_supported_versions_ext_type, ushort, 1 ) \
399 0 : FIELD( 1, &ext_supported_versions_ext_sz, ushort, 1 ) \
400 0 : FIELD( 2, ext_supported_versions, ushort, 1 ) \
401 0 : FIELD( 3, &ext_key_share_ext_type, ushort, 1 ) \
402 0 : FIELD( 4, &ext_key_share_ext_sz, ushort, 1 ) \
403 0 : FIELD( 5, &ext_key_share_group, ushort, 1 ) \
404 0 : FIELD( 6, &ext_key_share_sz, ushort, 1 ) \
405 0 : FIELD( 7, &in->key_share.x25519[0], uchar, 32UL )
406 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
407 0 : # undef FIELDS
408 :
409 0 : *extension_tot_sz = fd_ushort_bswap( (ushort)( (ulong)wire_laddr - extension_start ) );
410 0 : return (long)( wire_laddr - (ulong)wire );
411 0 : }
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 0 : ulong wire_sz ) {
466 :
467 0 : ulong wire_laddr = (ulong)wire;
468 :
469 0 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
470 0 : ushort ext_type;
471 0 : ushort ext_sz;
472 0 : # define FIELDS( FIELD ) \
473 0 : FIELD( 0, &ext_type, ushort, 1 ) \
474 0 : FIELD( 1, &ext_sz, ushort, 1 )
475 0 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
476 0 : # undef FIELDS
477 :
478 : /* Bounds check extension data
479 : (list_stop declared by DECODE_LIST macro) */
480 0 : if( FD_UNLIKELY( wire_laddr + ext_sz > list_stop ) )
481 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
482 :
483 0 : switch( ext_type ) {
484 0 : case FD_TLS_EXT_ALPN: {
485 0 : long res = fd_tls_decode_ext_alpn( &out->alpn, (uchar const *)wire_laddr, ext_sz );
486 0 : if( FD_UNLIKELY( res<0L ) )
487 0 : return res;
488 0 : if( FD_UNLIKELY( res!=(long)ext_sz ) )
489 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
490 0 : break;
491 0 : }
492 0 : case FD_TLS_EXT_QUIC_TRANSPORT_PARAMS:
493 0 : if( FD_UNLIKELY( ext_sz > FD_TLS_EXT_QUIC_PARAMS_SZ_MAX ) )
494 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
495 0 : out->quic_tp.buf = (void *)wire_laddr;
496 0 : out->quic_tp.bufsz = (ushort)ext_sz;
497 0 : 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 0 : }
511 :
512 0 : wire_laddr += ext_sz;
513 0 : wire_sz -= ext_sz;
514 0 : }
515 0 : FD_TLS_DECODE_LIST_END
516 :
517 : /* TODO Fail if trailing bytes detected? */
518 :
519 0 : return (long)( wire_laddr - (ulong)wire );
520 0 : }
521 :
522 : long
523 : fd_tls_encode_cert_x509( uchar const * x509,
524 : ulong x509_sz,
525 : uchar * wire,
526 0 : ulong wire_sz ) {
527 :
528 0 : ulong wire_laddr = (ulong)wire;
529 :
530 : /* TLS Record Header */
531 0 : 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 0 : fd_tls_u24_t msg_sz = fd_uint_to_tls_u24( (uint)( x509_sz + 9UL ) );
537 0 : fd_tls_u24_t cert_list_sz = fd_uint_to_tls_u24( (uint)( x509_sz + 5UL ) );
538 0 : 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 0 : uchar certificate_request_context_sz = (uchar)0;
543 :
544 : /* No certificate extensions */
545 0 : ushort ext_sz = (ushort)0;
546 :
547 0 : # define FIELDS( FIELD ) \
548 0 : FIELD( 0, &msg_type, uchar, 1 ) \
549 0 : FIELD( 1, &msg_sz, tls_u24, 1 ) \
550 0 : FIELD( 2, &certificate_request_context_sz, uchar, 1 ) \
551 0 : FIELD( 3, &cert_list_sz, tls_u24, 1 ) \
552 0 : FIELD( 4, &cert_sz, tls_u24, 1 ) \
553 0 : FIELD( 5, x509, uchar, x509_sz ) \
554 0 : FIELD( 6, &ext_sz, ushort, 1 )
555 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
556 0 : # undef FIELDS
557 :
558 0 : return (long)( wire_laddr - (ulong)wire );
559 0 : }
560 :
561 : long
562 : fd_tls_encode_enc_ext( fd_tls_enc_ext_t const * in,
563 : uchar * wire,
564 0 : ulong wire_sz ) {
565 :
566 0 : ulong wire_laddr = (ulong)wire;
567 :
568 : /* ALPN */
569 :
570 0 : if( in->alpn.bufsz ) {
571 0 : fd_tls_ext_hdr_t ext_hdr = { .type = FD_TLS_EXT_ALPN,
572 0 : .sz = (ushort)( in->alpn.bufsz+2 ) };
573 0 : FD_TLS_ENCODE_SUB( fd_tls_encode_ext_hdr, &ext_hdr );
574 0 : FD_TLS_ENCODE_SUB( fd_tls_encode_ext_alpn, &in->alpn );
575 0 : }
576 :
577 : /* QUIC transport params */
578 :
579 0 : if( in->quic_tp.buf ) {
580 0 : ushort ext_type = FD_TLS_EXT_QUIC_TRANSPORT_PARAMS;
581 0 : ushort ext_sz = (ushort)in->quic_tp.bufsz;
582 0 : # define FIELDS( FIELD ) \
583 0 : FIELD( 0, &ext_type, ushort, 1 ) \
584 0 : FIELD( 1, &ext_sz, ushort, 1 ) \
585 0 : FIELD( 2, in->quic_tp.buf, uchar, in->quic_tp.bufsz )
586 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
587 0 : # undef FIELDS
588 0 : }
589 :
590 : /* Server certificate type */
591 :
592 0 : 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 0 : 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 0 : return (long)( wire_laddr - (ulong)wire );
619 0 : }
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 0 : ulong wire_sz ) {
665 :
666 0 : ulong wire_laddr = (ulong)wire;
667 :
668 0 : ushort sig_sz;
669 0 : # define FIELDS( FIELD ) \
670 0 : FIELD( 0, &out->sig_alg, ushort, 1 ) \
671 0 : FIELD( 1, &sig_sz, ushort, 1 ) \
672 0 : FIELD( 2, out->sig, uchar, 64 )
673 0 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
674 0 : # undef FIELDS
675 :
676 0 : if( FD_UNLIKELY( ( out->sig_alg != FD_TLS_SIGNATURE_ED25519 )
677 0 : | ( sig_sz != 0x40UL ) ) )
678 0 : return -(long)FD_TLS_ALERT_ILLEGAL_PARAMETER;
679 :
680 0 : return (long)( wire_laddr - (ulong)wire );
681 0 : }
682 :
683 : long
684 : fd_tls_encode_cert_verify( fd_tls_cert_verify_t const * in,
685 : uchar * wire,
686 0 : ulong wire_sz ) {
687 :
688 0 : ulong wire_laddr = (ulong)wire;
689 :
690 0 : ushort sig_sz = 0x40;
691 0 : # define FIELDS( FIELD ) \
692 0 : FIELD( 0, &in->sig_alg, ushort, 1 ) \
693 0 : FIELD( 1, &sig_sz, ushort, 1 ) \
694 0 : FIELD( 2, in->sig, uchar, 64 )
695 0 : FD_TLS_ENCODE_STATIC_BATCH( FIELDS )
696 0 : # undef FIELDS
697 :
698 0 : return (long)( wire_laddr - (ulong)wire );
699 0 : }
700 :
701 : long
702 : fd_tls_decode_ext_server_name( fd_tls_ext_server_name_t * out,
703 : uchar const * wire,
704 0 : ulong wire_sz ) {
705 :
706 0 : ulong wire_laddr = (ulong)wire;
707 :
708 : /* TLS v1.3 server name lists practically always have one element. */
709 :
710 0 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
711 : /* Read type and length */
712 0 : uchar name_type;
713 0 : ushort name_sz;
714 0 : # define FIELDS( FIELD ) \
715 0 : FIELD( 0, &name_type, uchar, 1 ) \
716 0 : FIELD( 1, &name_sz, ushort, 1 )
717 0 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
718 0 : # undef FIELDS
719 :
720 : /* Bounds check name */
721 0 : 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 0 : if( ( ( name_type == FD_TLS_SERVER_NAME_TYPE_DNS )
726 0 : & ( name_sz < 254 )
727 0 : & ( out->host_name_len == 0 ) ) ) {
728 0 : out->host_name_len = (uchar)name_sz;
729 0 : memcpy( out->host_name, (uchar const *)wire_laddr, name_sz );
730 0 : out->host_name[ name_sz ] = '\0';
731 0 : }
732 :
733 : /* Seek to next name */
734 0 : wire_laddr += name_sz;
735 0 : wire_sz -= name_sz;
736 0 : }
737 0 : FD_TLS_DECODE_LIST_END
738 :
739 0 : return (long)( wire_laddr - (ulong)wire );
740 0 : }
741 :
742 : long
743 : fd_tls_decode_ext_supported_groups( fd_tls_ext_supported_groups_t * out,
744 : uchar const * wire,
745 0 : ulong wire_sz ) {
746 :
747 0 : ulong wire_laddr = (ulong)wire;
748 :
749 0 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
750 0 : ushort group;
751 0 : FD_TLS_DECODE_FIELD( &group, ushort );
752 0 : switch( group ) {
753 0 : case FD_TLS_GROUP_X25519:
754 0 : out->x25519 = 1;
755 0 : break;
756 0 : default:
757 : /* Ignore unsupported groups ... */
758 0 : break;
759 0 : }
760 0 : }
761 0 : FD_TLS_DECODE_LIST_END
762 :
763 0 : return (long)( wire_laddr - (ulong)wire );
764 0 : }
765 :
766 : long
767 : fd_tls_decode_ext_supported_versions( fd_tls_ext_supported_versions_t * out,
768 : uchar const * wire,
769 0 : ulong wire_sz ) {
770 :
771 0 : ulong wire_laddr = (ulong)wire;
772 :
773 0 : FD_TLS_DECODE_LIST_BEGIN( uchar, alignof(ushort) ) {
774 0 : ushort group;
775 0 : FD_TLS_DECODE_FIELD( &group, ushort );
776 0 : switch( group ) {
777 0 : case FD_TLS_VERSION_TLS13:
778 0 : out->tls13 = 1;
779 0 : break;
780 0 : default:
781 : /* Ignore unsupported TLS versions ... */
782 0 : break;
783 0 : }
784 0 : }
785 0 : FD_TLS_DECODE_LIST_END
786 :
787 0 : return (long)( wire_laddr - (ulong)wire );
788 0 : }
789 :
790 : long
791 : fd_tls_decode_ext_signature_algorithms( fd_tls_ext_signature_algorithms_t * out,
792 : uchar const * wire,
793 0 : ulong wire_sz ) {
794 :
795 0 : ulong wire_laddr = (ulong)wire;
796 :
797 0 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(ushort) ) {
798 0 : ushort group;
799 0 : FD_TLS_DECODE_FIELD( &group, ushort );
800 0 : switch( group ) {
801 0 : case FD_TLS_SIGNATURE_ED25519:
802 0 : out->ed25519 = 1;
803 0 : break;
804 0 : default:
805 : /* Ignore unsupported signature algorithms ... */
806 0 : break;
807 0 : }
808 0 : }
809 0 : FD_TLS_DECODE_LIST_END
810 :
811 0 : return (long)( wire_laddr - (ulong)wire );
812 0 : }
813 :
814 : long
815 : fd_tls_decode_key_share( fd_tls_key_share_t * out,
816 : uchar const * wire,
817 0 : ulong wire_sz ) {
818 :
819 0 : ulong wire_laddr = (ulong)wire;
820 :
821 : /* Read type and length */
822 0 : ushort group;
823 0 : ushort kex_data_sz;
824 0 : # define FIELDS( FIELD ) \
825 0 : FIELD( 0, &group, ushort, 1 ) \
826 0 : FIELD( 1, &kex_data_sz, ushort, 1 )
827 0 : FD_TLS_DECODE_STATIC_BATCH( FIELDS )
828 0 : # undef FIELDS
829 :
830 : /* Bounds check */
831 0 : if( FD_UNLIKELY( kex_data_sz > wire_sz ) )
832 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
833 :
834 0 : switch( group ) {
835 0 : case FD_TLS_GROUP_X25519:
836 0 : if( FD_UNLIKELY( kex_data_sz != 32UL ) )
837 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
838 0 : out->has_x25519 = 1;
839 0 : memcpy( out->x25519, (uchar const *)wire_laddr, 32UL );
840 0 : break;
841 0 : default:
842 : /* Ignore unsupported key share groups ... */
843 0 : break;
844 0 : }
845 :
846 : /* Seek to next group */
847 0 : wire_laddr += kex_data_sz;
848 0 : wire_sz -= kex_data_sz;
849 :
850 0 : return (long)( wire_laddr - (ulong)wire );
851 0 : }
852 :
853 : long
854 : fd_tls_decode_key_share_list( fd_tls_key_share_t * out,
855 : uchar const * wire,
856 0 : ulong wire_sz ) {
857 :
858 0 : ulong wire_laddr = (ulong)wire;
859 :
860 0 : FD_TLS_DECODE_LIST_BEGIN( ushort, alignof(uchar) ) {
861 0 : FD_TLS_DECODE_SUB( fd_tls_decode_key_share, out );
862 0 : }
863 0 : FD_TLS_DECODE_LIST_END
864 :
865 0 : return (long)( wire_laddr - (ulong)wire );
866 0 : }
867 :
868 : long
869 : fd_tls_decode_ext_cert_type_list( fd_tls_ext_cert_type_list_t * out,
870 : uchar const * wire,
871 0 : ulong wire_sz ) {
872 :
873 0 : ulong wire_laddr = (ulong)wire;
874 :
875 0 : out->present = 1;
876 0 : FD_TLS_DECODE_LIST_BEGIN( uchar, alignof(uchar) ) {
877 0 : uchar cert_type;
878 0 : FD_TLS_DECODE_FIELD( &cert_type, uchar ); /* is this really a uchar? */
879 0 : switch( cert_type ) {
880 0 : case FD_TLS_CERTTYPE_X509: out->x509 = 1; break;
881 0 : case FD_TLS_CERTTYPE_RAW_PUBKEY: out->raw_pubkey = 1; break;
882 0 : default:
883 : /* Ignore unsupported cert types ... */
884 0 : break;
885 0 : }
886 0 : }
887 0 : FD_TLS_DECODE_LIST_END
888 :
889 0 : return (long)( wire_laddr - (ulong)wire );
890 0 : }
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 0 : ulong wire_sz ) {
933 0 : out->buf = wire;
934 0 : out->bufsz = wire_sz;
935 0 : return (long)wire_sz;
936 0 : }
937 :
938 : long
939 : fd_tls_decode_ext_alpn( fd_tls_ext_alpn_t * const out,
940 : uchar const * const wire,
941 0 : ulong wire_sz ) {
942 0 : ulong wire_laddr = (ulong)wire;
943 0 : ushort alpn_sz;
944 0 : FD_TLS_DECODE_FIELD( &alpn_sz, ushort );
945 0 : if( FD_UNLIKELY( (ulong)alpn_sz != wire_sz ) )
946 0 : return -(long)FD_TLS_ALERT_DECODE_ERROR;
947 0 : return 2L + (long)fd_tls_decode_ext_opaque( out, (uchar const *)wire_laddr, wire_sz );
948 0 : }
949 :
950 : long
951 : fd_tls_encode_ext_alpn( fd_tls_ext_alpn_t const * in,
952 : uchar * wire,
953 0 : ulong wire_sz ) {
954 0 : ulong sz = 2UL + in->bufsz;
955 0 : if( FD_UNLIKELY( sz>wire_sz ) )
956 0 : return -(long)FD_TLS_ALERT_INTERNAL_ERROR;
957 0 : wire[0] = (uchar)( (in->bufsz >> 8)&0xFF );
958 0 : wire[1] = (uchar)( in->bufsz &0xFF );
959 0 : fd_memcpy( wire+2UL, in->buf, in->bufsz );
960 0 : return (long)sz;
961 0 : }
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 0 : uchar const ** const out_pubkey ) {
974 0 : uchar const * pubkey = fd_x509_mock_pubkey( cert, cert_sz );
975 0 : if( FD_UNLIKELY( !pubkey ) )
976 0 : return FD_TLS_ALERT_UNSUPPORTED_CERTIFICATE;
977 0 : *out_pubkey = pubkey;
978 0 : return 0U;
979 0 : }
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 0 : uint cert_type ) {
986 :
987 0 : fd_memset( res, 0, sizeof(fd_tls_extract_cert_pubkey_res_t) );
988 :
989 0 : ulong wire_laddr = (ulong)cert_chain;
990 0 : ulong wire_sz = cert_chain_sz;
991 :
992 : /* Skip 'opaque certificate_request_context<0..2^8-1>' */
993 0 : uchar const * opaque_sz = FD_TLS_SKIP_FIELD( uchar );
994 0 : 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 0 : 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 0 : uint cert_list_sz = fd_tls_u24_to_uint( cert_list_sz_ );
1002 0 : 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 0 : 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 0 : uint cert_sz = fd_tls_u24_to_uint( cert_sz_ );
1012 0 : 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 0 : void * cert = (void *)wire_laddr;
1019 :
1020 0 : switch( cert_type ) {
1021 :
1022 0 : case FD_TLS_CERTTYPE_X509: {
1023 :
1024 : /* DER-encoded X.509 certificate */
1025 :
1026 0 : uint x509_alert = fd_tls_client_handle_x509( cert, cert_sz, &res->pubkey );
1027 0 : 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 0 : return 0L;
1035 0 : }
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 : FD_LOG_CRIT(( "invalid certificate type %u", cert_type ));
1054 :
1055 0 : } /* end switch */
1056 0 : }
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 0 : uint cert_type ) {
1062 0 : fd_tls_extract_cert_pubkey_res_t res;
1063 0 : long ret = fd_tls_extract_cert_pubkey_( &res, cert_chain, cert_chain_sz, cert_type );
1064 0 : (void)ret;
1065 0 : return res;
1066 0 : }
|