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