xref: /openbsd-src/regress/lib/libssl/handshake/handshake_table.c (revision f49eea4ee3f657a8d4c54e6d5d6e9324310c9cb1)
1*f49eea4eStb /*	$OpenBSD: handshake_table.c,v 1.18 2022/12/01 13:49:12 tb Exp $	*/
2c4d50951Stb /*
3c4d50951Stb  * Copyright (c) 2019 Theo Buehler <tb@openbsd.org>
4c4d50951Stb  *
5c4d50951Stb  * Permission to use, copy, modify, and distribute this software for any
6c4d50951Stb  * purpose with or without fee is hereby granted, provided that the above
7c4d50951Stb  * copyright notice and this permission notice appear in all copies.
8c4d50951Stb  *
9c4d50951Stb  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10c4d50951Stb  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11c4d50951Stb  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12c4d50951Stb  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13c4d50951Stb  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14c4d50951Stb  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15c4d50951Stb  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16c4d50951Stb  */
17c4d50951Stb 
18c4d50951Stb #include <err.h>
19c4d50951Stb #include <stdint.h>
20c4d50951Stb #include <stdio.h>
21c4d50951Stb #include <stdlib.h>
22c4d50951Stb #include <unistd.h>
23c4d50951Stb 
24c4d50951Stb #include "tls13_handshake.h"
25c4d50951Stb 
26278a4720Stb #define MAX_FLAGS (UINT8_MAX + 1)
27278a4720Stb 
28c4d50951Stb /*
29c4d50951Stb  * From RFC 8446:
30c4d50951Stb  *
31c4d50951Stb  * Appendix A.  State Machine
32c4d50951Stb  *
33c4d50951Stb  *    This appendix provides a summary of the legal state transitions for
34c4d50951Stb  *    the client and server handshakes.  State names (in all capitals,
35c4d50951Stb  *    e.g., START) have no formal meaning but are provided for ease of
36c4d50951Stb  *    comprehension.  Actions which are taken only in certain circumstances
37c4d50951Stb  *    are indicated in [].  The notation "K_{send,recv} = foo" means "set
38c4d50951Stb  *    the send/recv key to the given key".
39c4d50951Stb  *
40c4d50951Stb  * A.1.  Client
41c4d50951Stb  *
42c4d50951Stb  *                               START <----+
43c4d50951Stb  *                Send ClientHello |        | Recv HelloRetryRequest
44c4d50951Stb  *           [K_send = early data] |        |
45c4d50951Stb  *                                 v        |
46c4d50951Stb  *            /                 WAIT_SH ----+
47c4d50951Stb  *            |                    | Recv ServerHello
48c4d50951Stb  *            |                    | K_recv = handshake
49c4d50951Stb  *        Can |                    V
50c4d50951Stb  *       send |                 WAIT_EE
51c4d50951Stb  *      early |                    | Recv EncryptedExtensions
52c4d50951Stb  *       data |           +--------+--------+
53c4d50951Stb  *            |     Using |                 | Using certificate
54c4d50951Stb  *            |       PSK |                 v
55c4d50951Stb  *            |           |            WAIT_CERT_CR
56c4d50951Stb  *            |           |        Recv |       | Recv CertificateRequest
57c4d50951Stb  *            |           | Certificate |       v
58c4d50951Stb  *            |           |             |    WAIT_CERT
59c4d50951Stb  *            |           |             |       | Recv Certificate
60c4d50951Stb  *            |           |             v       v
61c4d50951Stb  *            |           |              WAIT_CV
62c4d50951Stb  *            |           |                 | Recv CertificateVerify
63c4d50951Stb  *            |           +> WAIT_FINISHED <+
64c4d50951Stb  *            |                  | Recv Finished
65c4d50951Stb  *            \                  | [Send EndOfEarlyData]
66c4d50951Stb  *                               | K_send = handshake
67c4d50951Stb  *                               | [Send Certificate [+ CertificateVerify]]
68c4d50951Stb  *     Can send                  | Send Finished
69c4d50951Stb  *     app data   -->            | K_send = K_recv = application
70c4d50951Stb  *     after here                v
71c4d50951Stb  *                           CONNECTED
72c4d50951Stb  *
73c4d50951Stb  *    Note that with the transitions as shown above, clients may send
74c4d50951Stb  *    alerts that derive from post-ServerHello messages in the clear or
75c4d50951Stb  *    with the early data keys.  If clients need to send such alerts, they
76c4d50951Stb  *    SHOULD first rekey to the handshake keys if possible.
77c4d50951Stb  *
78c4d50951Stb  */
79c4d50951Stb 
80c4d50951Stb struct child {
81c4d50951Stb 	enum tls13_message_type	mt;
82c4d50951Stb 	uint8_t			flag;
83c4d50951Stb 	uint8_t			forced;
84c4d50951Stb 	uint8_t			illegal;
85c4d50951Stb };
86c4d50951Stb 
87c4d50951Stb static struct child stateinfo[][TLS13_NUM_MESSAGE_TYPES] = {
88c4d50951Stb 	[CLIENT_HELLO] = {
892f94b75cStb 		{
902f94b75cStb 			.mt = SERVER_HELLO_RETRY_REQUEST,
912f94b75cStb 		},
922f94b75cStb 		{
932f94b75cStb 			.mt = SERVER_HELLO,
942f94b75cStb 			.flag = WITHOUT_HRR,
952f94b75cStb 		},
96e1330927Sjsing 	},
97e1330927Sjsing 	[SERVER_HELLO_RETRY_REQUEST] = {
982f94b75cStb 		{
992f94b75cStb 			.mt = CLIENT_HELLO_RETRY,
1002f94b75cStb 		},
101e1330927Sjsing 	},
102e1330927Sjsing 	[CLIENT_HELLO_RETRY] = {
1032f94b75cStb 		{
1042f94b75cStb 			.mt = SERVER_HELLO,
1052f94b75cStb 		},
106c4d50951Stb 	},
107c4d50951Stb 	[SERVER_HELLO] = {
1082f94b75cStb 		{
1092f94b75cStb 			.mt = SERVER_ENCRYPTED_EXTENSIONS,
1102f94b75cStb 		},
111c4d50951Stb 	},
112c4d50951Stb 	[SERVER_ENCRYPTED_EXTENSIONS] = {
1132f94b75cStb 		{
1142f94b75cStb 			.mt = SERVER_CERTIFICATE_REQUEST,
1152f94b75cStb 		},
1162f94b75cStb 		{	.mt = SERVER_CERTIFICATE,
1172f94b75cStb 			.flag = WITHOUT_CR,
1182f94b75cStb 		},
1192f94b75cStb 		{
1202f94b75cStb 			.mt = SERVER_FINISHED,
1212f94b75cStb 			.flag = WITH_PSK,
1222f94b75cStb 		},
123c4d50951Stb 	},
124c4d50951Stb 	[SERVER_CERTIFICATE_REQUEST] = {
1252f94b75cStb 		{
1262f94b75cStb 			.mt = SERVER_CERTIFICATE,
1272f94b75cStb 		},
128c4d50951Stb 	},
129c4d50951Stb 	[SERVER_CERTIFICATE] = {
1302f94b75cStb 		{
1312f94b75cStb 			.mt = SERVER_CERTIFICATE_VERIFY,
1322f94b75cStb 		},
133c4d50951Stb 	},
134c4d50951Stb 	[SERVER_CERTIFICATE_VERIFY] = {
1352f94b75cStb 		{
1362f94b75cStb 			.mt = SERVER_FINISHED,
1372f94b75cStb 		},
138c4d50951Stb 	},
139c4d50951Stb 	[SERVER_FINISHED] = {
1402f94b75cStb 		{
1412f94b75cStb 			.mt = CLIENT_FINISHED,
1422f94b75cStb 			.forced = WITHOUT_CR | WITH_PSK,
1432f94b75cStb 		},
1442f94b75cStb 		{
1452f94b75cStb 			.mt = CLIENT_CERTIFICATE,
1462f94b75cStb 			.illegal = WITHOUT_CR | WITH_PSK,
1472f94b75cStb 		},
148c4d50951Stb 	},
149c4d50951Stb 	[CLIENT_CERTIFICATE] = {
1502f94b75cStb 		{
1512f94b75cStb 			.mt = CLIENT_FINISHED,
1522f94b75cStb 		},
1532f94b75cStb 		{
1542f94b75cStb 			.mt = CLIENT_CERTIFICATE_VERIFY,
1552f94b75cStb 			.flag = WITH_CCV,
1562f94b75cStb 		},
157c4d50951Stb 	},
158c4d50951Stb 	[CLIENT_CERTIFICATE_VERIFY] = {
1592f94b75cStb 		{
1602f94b75cStb 			.mt = CLIENT_FINISHED,
1612f94b75cStb 		},
162c4d50951Stb 	},
163c4d50951Stb 	[CLIENT_FINISHED] = {
1642f94b75cStb 		{
1652f94b75cStb 			.mt = APPLICATION_DATA,
1662f94b75cStb 		},
167c4d50951Stb 	},
168c4d50951Stb 	[APPLICATION_DATA] = {
1692f94b75cStb 		{
1702f94b75cStb 			.mt = 0,
1712f94b75cStb 		},
172c4d50951Stb 	},
173c4d50951Stb };
174c4d50951Stb 
175c4b3591aStb const size_t	 stateinfo_count = sizeof(stateinfo) / sizeof(stateinfo[0]);
176c4b3591aStb 
177c4d50951Stb void		 build_table(enum tls13_message_type
178dab6c58aStb 		     table[MAX_FLAGS][TLS13_NUM_MESSAGE_TYPES],
1797a668e62Stb 		     struct child current, struct child end,
1807a668e62Stb 		     struct child path[], uint8_t flags, unsigned int depth);
1818d6bcc7aStb size_t		 count_handshakes(void);
1827a668e62Stb void		 edge(enum tls13_message_type start,
1837a668e62Stb 		     enum tls13_message_type end, uint8_t flag);
1848d6bcc7aStb const char	*flag2str(uint8_t flag);
1857a668e62Stb void		 flag_label(uint8_t flag);
1867a668e62Stb void		 forced_edges(enum tls13_message_type start,
1877a668e62Stb 		     enum tls13_message_type end, uint8_t forced);
188c4b3591aStb int		 generate_graphics(void);
189a6ee115cStb void		 fprint_entry(FILE *stream,
1907a668e62Stb 		     enum tls13_message_type path[TLS13_NUM_MESSAGE_TYPES],
1917a668e62Stb 		     uint8_t flags);
192a6ee115cStb void		 fprint_flags(FILE *stream, uint8_t flags);
1938d6bcc7aStb const char	*mt2str(enum tls13_message_type mt);
19496683f33Stb void		 usage(void);
195c4d50951Stb int		 verify_table(enum tls13_message_type
196dab6c58aStb 		     table[MAX_FLAGS][TLS13_NUM_MESSAGE_TYPES], int print);
197c4d50951Stb 
198c4d50951Stb const char *
flag2str(uint8_t flag)199c4d50951Stb flag2str(uint8_t flag)
200c4d50951Stb {
201c4d50951Stb 	const char *ret;
202c4d50951Stb 
203c4d50951Stb 	if (flag & (flag - 1))
204c4d50951Stb 		errx(1, "more than one bit is set");
205c4d50951Stb 
206c4d50951Stb 	switch (flag) {
2073d034219Stb 	case INITIAL:
2083d034219Stb 		ret = "INITIAL";
209c4d50951Stb 		break;
210c4d50951Stb 	case NEGOTIATED:
211c4d50951Stb 		ret = "NEGOTIATED";
212c4d50951Stb 		break;
213c4d50951Stb 	case WITHOUT_CR:
214c4d50951Stb 		ret = "WITHOUT_CR";
215c4d50951Stb 		break;
216e1330927Sjsing 	case WITHOUT_HRR:
217e1330927Sjsing 		ret = "WITHOUT_HRR";
218c4d50951Stb 		break;
219c4d50951Stb 	case WITH_PSK:
220c4d50951Stb 		ret = "WITH_PSK";
221c4d50951Stb 		break;
222c4d50951Stb 	case WITH_CCV:
223c4d50951Stb 		ret = "WITH_CCV";
224c4d50951Stb 		break;
225c4d50951Stb 	case WITH_0RTT:
226c4d50951Stb 		ret = "WITH_0RTT";
227c4d50951Stb 		break;
228c4d50951Stb 	default:
229c4d50951Stb 		ret = "UNKNOWN";
230c4d50951Stb 	}
231c4d50951Stb 
232c4d50951Stb 	return ret;
233c4d50951Stb }
234c4d50951Stb 
235c4d50951Stb const char *
mt2str(enum tls13_message_type mt)236c4d50951Stb mt2str(enum tls13_message_type mt)
237c4d50951Stb {
238c4d50951Stb 	const char *ret;
239c4d50951Stb 
240c4d50951Stb 	switch (mt) {
241c4d50951Stb 	case INVALID:
242c4d50951Stb 		ret = "INVALID";
243c4d50951Stb 		break;
244c4d50951Stb 	case CLIENT_HELLO:
245c4d50951Stb 		ret = "CLIENT_HELLO";
246c4d50951Stb 		break;
247c4d50951Stb 	case CLIENT_HELLO_RETRY:
248c4d50951Stb 		ret = "CLIENT_HELLO_RETRY";
249c4d50951Stb 		break;
250c4d50951Stb 	case CLIENT_END_OF_EARLY_DATA:
251c4d50951Stb 		ret = "CLIENT_END_OF_EARLY_DATA";
252c4d50951Stb 		break;
253c4d50951Stb 	case CLIENT_CERTIFICATE:
254c4d50951Stb 		ret = "CLIENT_CERTIFICATE";
255c4d50951Stb 		break;
256c4d50951Stb 	case CLIENT_CERTIFICATE_VERIFY:
257c4d50951Stb 		ret = "CLIENT_CERTIFICATE_VERIFY";
258c4d50951Stb 		break;
259c4d50951Stb 	case CLIENT_FINISHED:
260c4d50951Stb 		ret = "CLIENT_FINISHED";
261c4d50951Stb 		break;
262c4d50951Stb 	case SERVER_HELLO:
263c4d50951Stb 		ret = "SERVER_HELLO";
264c4d50951Stb 		break;
265e1330927Sjsing 	case SERVER_HELLO_RETRY_REQUEST:
266e1330927Sjsing 		ret = "SERVER_HELLO_RETRY_REQUEST";
267397bafb9Stb 		break;
268c4d50951Stb 	case SERVER_ENCRYPTED_EXTENSIONS:
269c4d50951Stb 		ret = "SERVER_ENCRYPTED_EXTENSIONS";
270c4d50951Stb 		break;
271c4d50951Stb 	case SERVER_CERTIFICATE:
272c4d50951Stb 		ret = "SERVER_CERTIFICATE";
273c4d50951Stb 		break;
274c4d50951Stb 	case SERVER_CERTIFICATE_VERIFY:
275c4d50951Stb 		ret = "SERVER_CERTIFICATE_VERIFY";
276c4d50951Stb 		break;
277c4d50951Stb 	case SERVER_CERTIFICATE_REQUEST:
278c4d50951Stb 		ret = "SERVER_CERTIFICATE_REQUEST";
279c4d50951Stb 		break;
280c4d50951Stb 	case SERVER_FINISHED:
281c4d50951Stb 		ret = "SERVER_FINISHED";
282c4d50951Stb 		break;
283c4d50951Stb 	case APPLICATION_DATA:
284c4d50951Stb 		ret = "APPLICATION_DATA";
285c4d50951Stb 		break;
286c4d50951Stb 	case TLS13_NUM_MESSAGE_TYPES:
287c4d50951Stb 		ret = "TLS13_NUM_MESSAGE_TYPES";
288c4d50951Stb 		break;
289c4d50951Stb 	default:
290c4d50951Stb 		ret = "UNKNOWN";
291c4d50951Stb 		break;
292c4d50951Stb 	}
293c4d50951Stb 
294c4d50951Stb 	return ret;
295c4d50951Stb }
296c4d50951Stb 
297c4d50951Stb void
fprint_flags(FILE * stream,uint8_t flags)298a6ee115cStb fprint_flags(FILE *stream, uint8_t flags)
299c4d50951Stb {
300c4d50951Stb 	int first = 1, i;
301c4d50951Stb 
3023d034219Stb 	if (flags == 0) {
303a6ee115cStb 		fprintf(stream, "%s", flag2str(flags));
3043d034219Stb 		return;
3053d034219Stb 	}
3063d034219Stb 
307c4d50951Stb 	for (i = 0; i < 8; i++) {
308c4d50951Stb 		uint8_t set = flags & (1U << i);
309c4d50951Stb 
310c4d50951Stb 		if (set) {
311a6ee115cStb 			fprintf(stream, "%s%s", first ? "" : " | ",
312a6ee115cStb 			    flag2str(set));
313c4d50951Stb 			first = 0;
314c4d50951Stb 		}
315c4d50951Stb 	}
316c4d50951Stb }
317c4d50951Stb 
318c4d50951Stb void
fprint_entry(FILE * stream,enum tls13_message_type path[TLS13_NUM_MESSAGE_TYPES],uint8_t flags)3197a668e62Stb fprint_entry(FILE *stream,
3207a668e62Stb     enum tls13_message_type path[TLS13_NUM_MESSAGE_TYPES], uint8_t flags)
321c4d50951Stb {
322c4d50951Stb 	int i;
323c4d50951Stb 
324a6ee115cStb 	fprintf(stream, "\t[");
325a6ee115cStb 	fprint_flags(stream, flags);
326a6ee115cStb 	fprintf(stream, "] = {\n");
327c4d50951Stb 
328c4d50951Stb 	for (i = 0; i < TLS13_NUM_MESSAGE_TYPES; i++) {
329c4d50951Stb 		if (path[i] == 0)
330c4d50951Stb 			break;
331a6ee115cStb 		fprintf(stream, "\t\t%s,\n", mt2str(path[i]));
332c4d50951Stb 	}
333a6ee115cStb 	fprintf(stream, "\t},\n");
334c4d50951Stb }
335c4d50951Stb 
3367a668e62Stb void
edge(enum tls13_message_type start,enum tls13_message_type end,uint8_t flag)3377a668e62Stb edge(enum tls13_message_type start, enum tls13_message_type end,
3387a668e62Stb     uint8_t flag)
3397a668e62Stb {
3407a668e62Stb 	printf("\t%s -> %s", mt2str(start), mt2str(end));
3417a668e62Stb 	flag_label(flag);
3427a668e62Stb 	printf(";\n");
3437a668e62Stb }
3447a668e62Stb 
3457a668e62Stb void
flag_label(uint8_t flag)3467a668e62Stb flag_label(uint8_t flag)
3477a668e62Stb {
3487a668e62Stb 	if (flag)
3497a668e62Stb 		printf(" [label=\"%s\"]", flag2str(flag));
3507a668e62Stb }
3517a668e62Stb 
3527a668e62Stb void
forced_edges(enum tls13_message_type start,enum tls13_message_type end,uint8_t forced)3537a668e62Stb forced_edges(enum tls13_message_type start, enum tls13_message_type end,
3547a668e62Stb     uint8_t forced)
3557a668e62Stb {
3567a668e62Stb 	uint8_t	forced_flag, i;
3577a668e62Stb 
3587a668e62Stb 	if (forced == 0)
3597a668e62Stb 		return;
3607a668e62Stb 
3617a668e62Stb 	for (i = 0; i < 8; i++) {
3627a668e62Stb 		forced_flag = forced & (1U << i);
3637a668e62Stb 		if (forced_flag)
3647a668e62Stb 			edge(start, end, forced_flag);
3657a668e62Stb 	}
3667a668e62Stb }
3677a668e62Stb 
368c4b3591aStb int
generate_graphics(void)369c4b3591aStb generate_graphics(void)
370c4b3591aStb {
3717a668e62Stb 	enum tls13_message_type	start, end;
3727a668e62Stb 	unsigned int		child;
373c4b3591aStb 	uint8_t			flag;
3747a668e62Stb 	uint8_t			forced;
375c4b3591aStb 
376c4b3591aStb 	printf("digraph G {\n");
3777a668e62Stb 	printf("\t%s [shape=box];\n", mt2str(CLIENT_HELLO));
3787a668e62Stb 	printf("\t%s [shape=box];\n", mt2str(APPLICATION_DATA));
379c4b3591aStb 
3807a668e62Stb 	for (start = CLIENT_HELLO; start < APPLICATION_DATA; start++) {
3817a668e62Stb 		for (child = 0; stateinfo[start][child].mt != 0; child++) {
3827a668e62Stb 			end = stateinfo[start][child].mt;
3837a668e62Stb 			flag = stateinfo[start][child].flag;
3847a668e62Stb 			forced = stateinfo[start][child].forced;
385c4b3591aStb 
3867a668e62Stb 			if (forced == 0)
3877a668e62Stb 				edge(start, end, flag);
3887a668e62Stb 			else
3897a668e62Stb 				forced_edges(start, end, forced);
390c4b3591aStb 		}
391c4b3591aStb 	}
392c4b3591aStb 
393c4b3591aStb 	printf("}\n");
394c4b3591aStb 	return 0;
395c4b3591aStb }
396c4b3591aStb 
3973d034219Stb extern enum tls13_message_type	handshakes[][TLS13_NUM_MESSAGE_TYPES];
3983d034219Stb extern size_t			handshake_count;
3993d034219Stb 
4003d034219Stb size_t
count_handshakes(void)4013d034219Stb count_handshakes(void)
4023d034219Stb {
4033d034219Stb 	size_t	ret = 0, i;
4043d034219Stb 
4053d034219Stb 	for (i = 0; i < handshake_count; i++) {
4063d034219Stb 		if (handshakes[i][0] != INVALID)
4073d034219Stb 			ret++;
4083d034219Stb 	}
4093d034219Stb 
4103d034219Stb 	return ret;
4113d034219Stb }
4123d034219Stb 
413c4d50951Stb void
build_table(enum tls13_message_type table[MAX_FLAGS][TLS13_NUM_MESSAGE_TYPES],struct child current,struct child end,struct child path[],uint8_t flags,unsigned int depth)414dab6c58aStb build_table(enum tls13_message_type table[MAX_FLAGS][TLS13_NUM_MESSAGE_TYPES],
415c4d50951Stb     struct child current, struct child end, struct child path[], uint8_t flags,
416c4d50951Stb     unsigned int depth)
417c4d50951Stb {
418c4d50951Stb 	unsigned int i;
419c4d50951Stb 
420c4d50951Stb 	if (depth >= TLS13_NUM_MESSAGE_TYPES - 1)
421c4d50951Stb 		errx(1, "recursed too deeply");
422c4d50951Stb 
423c4d50951Stb 	/* Record current node. */
424c4d50951Stb 	path[depth++] = current;
425c4d50951Stb 	flags |= current.flag;
426c4d50951Stb 
427c4d50951Stb 	/* If we haven't reached the end, recurse over the children. */
428c4d50951Stb 	if (current.mt != end.mt) {
429c4d50951Stb 		for (i = 0; stateinfo[current.mt][i].mt != 0; i++) {
430c4d50951Stb 			struct child child = stateinfo[current.mt][i];
431c4d50951Stb 			int forced = stateinfo[current.mt][i].forced;
432c4d50951Stb 			int illegal = stateinfo[current.mt][i].illegal;
433c4d50951Stb 
434c4d50951Stb 			if ((forced == 0 || (forced & flags)) &&
435c4d50951Stb 			    (illegal == 0 || !(illegal & flags)))
436c4d50951Stb 				build_table(table, child, end, path, flags,
437c4d50951Stb 				    depth);
438c4d50951Stb 		}
439c4d50951Stb 		return;
440c4d50951Stb 	}
441c4d50951Stb 
442c4d50951Stb 	if (flags == 0)
443c4d50951Stb 		errx(1, "path does not set flags");
444c4d50951Stb 
445c4d50951Stb 	if (table[flags][0] != 0)
446c4d50951Stb 		errx(1, "path traversed twice");
447c4d50951Stb 
448c4d50951Stb 	for (i = 0; i < depth; i++)
449c4d50951Stb 		table[flags][i] = path[i].mt;
450c4d50951Stb }
451c4d50951Stb 
452c4d50951Stb int
verify_table(enum tls13_message_type table[MAX_FLAGS][TLS13_NUM_MESSAGE_TYPES],int print)453dab6c58aStb verify_table(enum tls13_message_type table[MAX_FLAGS][TLS13_NUM_MESSAGE_TYPES],
454c4d50951Stb     int print)
455c4d50951Stb {
456c4d50951Stb 	int	success = 1, i;
4573d034219Stb 	size_t	num_valid, num_found = 0;
458c4d50951Stb 	uint8_t	flags = 0;
459c4d50951Stb 
460c4d50951Stb 	do {
461c4d50951Stb 		if (table[flags][0] == 0)
462c4d50951Stb 			continue;
463c4d50951Stb 
4643d034219Stb 		num_found++;
4653d034219Stb 
466c4d50951Stb 		for (i = 0; i < TLS13_NUM_MESSAGE_TYPES; i++) {
467c4d50951Stb 			if (table[flags][i] != handshakes[flags][i]) {
468a6ee115cStb 				fprintf(stderr,
469a6ee115cStb 				    "incorrect entry %d of handshake ", i);
470a6ee115cStb 				fprint_flags(stderr, flags);
471a6ee115cStb 				fprintf(stderr, "\n");
472c4d50951Stb 				success = 0;
473c4d50951Stb 			}
474c4d50951Stb 		}
475c4d50951Stb 
476c4d50951Stb 		if (print)
477a6ee115cStb 			fprint_entry(stdout, table[flags], flags);
4783d034219Stb 	} while(++flags != 0);
4793d034219Stb 
4803d034219Stb 	num_valid = count_handshakes();
4813d034219Stb 	if (num_valid != num_found) {
4829a54de93Stb 		fprintf(stderr,
4839a54de93Stb 		    "incorrect number of handshakes: want %zu, got %zu.\n",
4843d034219Stb 		    num_valid, num_found);
4853d034219Stb 		success = 0;
4863d034219Stb 	}
487c4d50951Stb 
488c4d50951Stb 	return success;
489c4d50951Stb }
490c4d50951Stb 
49196683f33Stb void
usage(void)492c4d50951Stb usage(void)
493c4d50951Stb {
494c4b3591aStb 	fprintf(stderr, "usage: handshake_table [-C | -g]\n");
495c4d50951Stb 	exit(1);
496c4d50951Stb }
497c4d50951Stb 
498c4d50951Stb int
main(int argc,char * argv[])499c4d50951Stb main(int argc, char *argv[])
500c4d50951Stb {
501c4d50951Stb 	static enum tls13_message_type
502dab6c58aStb 	    hs_table[MAX_FLAGS][TLS13_NUM_MESSAGE_TYPES] = {
5033d034219Stb 		[INITIAL] = {
5043d034219Stb 			CLIENT_HELLO,
505e1330927Sjsing 			SERVER_HELLO_RETRY_REQUEST,
506e1330927Sjsing 			CLIENT_HELLO_RETRY,
5073d034219Stb 			SERVER_HELLO,
5083d034219Stb 		},
5093d034219Stb 	};
510c4d50951Stb 	struct child	start = {
5112f94b75cStb 		.mt = CLIENT_HELLO,
512c4d50951Stb 	};
513c4d50951Stb 	struct child	end = {
5142f94b75cStb 		.mt = APPLICATION_DATA,
515c4d50951Stb 	};
516c4d50951Stb 	struct child	path[TLS13_NUM_MESSAGE_TYPES] = {{0}};
517f1baa6d0Stb 	uint8_t		flags = NEGOTIATED;
518c4d50951Stb 	unsigned int	depth = 0;
519c4b3591aStb 	int		ch, graphviz = 0, print = 0;
520c4d50951Stb 
521c4b3591aStb 	while ((ch = getopt(argc, argv, "Cg")) != -1) {
522c4d50951Stb 		switch (ch) {
523c4d50951Stb 		case 'C':
524c4d50951Stb 			print = 1;
525c4d50951Stb 			break;
526c4b3591aStb 		case 'g':
527c4b3591aStb 			graphviz = 1;
528c4b3591aStb 			break;
529c4d50951Stb 		default:
530c4d50951Stb 			usage();
531c4d50951Stb 		}
532c4d50951Stb 	}
533c4d50951Stb 	argc -= optind;
534c4d50951Stb 	argv += optind;
535c4d50951Stb 
536c4d50951Stb 	if (argc != 0)
537c4d50951Stb 		usage();
538c4d50951Stb 
539c4b3591aStb 	if (graphviz && print)
540c4b3591aStb 		usage();
541c4b3591aStb 
542c4b3591aStb 	if (graphviz)
543c4b3591aStb 		return generate_graphics();
544c4b3591aStb 
545c4d50951Stb 	build_table(hs_table, start, end, path, flags, depth);
546c4d50951Stb 	if (!verify_table(hs_table, print))
547c4d50951Stb 		return 1;
548c4d50951Stb 
549c4d50951Stb 	return 0;
550c4d50951Stb }
551