1 /*
2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License").
5 * You may not use this file except in compliance with the License.
6 * A copy of the License is located at
7 *
8 * http://aws.amazon.com/apache2.0
9 *
10 * or in the "license" file accompanying this file. This file is distributed
11 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12 * express or implied. See the License for the specific language governing
13 * permissions and limitations under the License.
14 */
15
16 #include <string.h>
17 #include <stdio.h>
18
19 #include "tls/s2n_handshake_io.c"
20
21 #define MAX_STATE_TYPE (APPLICATION_DATA + 1)
22
23 struct state {
24 const char *name;
25 int children[MAX_STATE_TYPE];
26 };
27
traverse_handshakes(message_type_t hs_table[S2N_HANDSHAKES_COUNT][S2N_MAX_HANDSHAKE_LENGTH],const char * version,const char * destination)28 int traverse_handshakes(message_type_t hs_table[S2N_HANDSHAKES_COUNT][S2N_MAX_HANDSHAKE_LENGTH], const char *version, const char *destination)
29 {
30 FILE *out;
31 char cmd[255];
32 const char *dot = "dot -Tsvg > %s";
33 snprintf(cmd, sizeof(cmd), dot, destination);
34
35 out = popen(cmd, "w");
36 if (!out) {
37 fprintf(stdout, "Failed to run graphviz. Check if you have graphviz installed?\n");
38 return 1;
39 }
40
41 struct state states[MAX_STATE_TYPE] = { 0 };
42
43 /* generate struct for all states */
44 struct state initial = { .name = "INITIAL" };
45
46 for (int i = CLIENT_HELLO; i < MAX_STATE_TYPE; i++) {
47 struct state node = { .name = message_names[i] };
48 states[i] = node;
49 }
50
51 /* traverse handshakes */
52 for (int i = 0; i < S2N_HANDSHAKES_COUNT; i++) {
53 /* to detect client_hello from empty 0-init value, we check for the following value */
54 if (!hs_table[i][1])
55 continue;
56
57 for (int j = 0; j < S2N_MAX_HANDSHAKE_LENGTH; j++) {
58 message_type_t msg = hs_table[i][j];
59 if (j > 0 && !msg)
60 continue;
61
62 /* register oneself as parent's child */
63 if (j == 0) {
64 initial.children[msg] = 1;
65 } else {
66 states[hs_table[i][j - 1]].children[msg] = 1;
67 }
68 }
69 }
70
71 /* find associated descendents of this node */
72 #define print_children(state) \
73 for (int c = 0; c < MAX_STATE_TYPE; c++) { \
74 if (!state.children[c]) continue; \
75 fprintf(out, " %s -> %s\n", state.name, states[c].name); \
76 }
77
78 /* produce dot format header */
79 fprintf(out, "digraph G {\n");
80 fprintf(out, " labelloc=\"t\";\n");
81 fprintf(out, " label=<<font point-size='24'>s2n TLS %s State Machine</font>>\n", version);
82
83 /* output initial root node */
84 print_children(initial);
85
86 /* iterate thru all possible nodes */
87 for (int i = CLIENT_HELLO; i < MAX_STATE_TYPE; i++) {
88 print_children(states[i]);
89 }
90
91 /* produce dot format footer */
92 fprintf(out, " INITIAL [shape=diamond];\n");
93 fprintf(out, " APPLICATION_DATA [shape=square];\n");
94 fprintf(out, "}");
95
96 pclose(out);
97
98 return 0;
99 }
100
101 /*
102 * This program generates a visualization of the s2n TLS state machine.
103 * It does so by generating a directed acyclic graph, before piping
104 * a dot graph format output to graphviz to generate svg files in the
105 * document image directory.
106 */
107
main(int argc,char ** argv)108 int main(int argc, char **argv)
109 {
110 fprintf(stdout, "Generating graphs for s2n TLS state machine...\n");
111 traverse_handshakes(handshakes, "1.2", "../../docs/images/tls12_state_machine.svg");
112 traverse_handshakes(tls13_handshakes, "1.3", "../../docs/images/tls13_state_machine.svg");
113 fprintf(stdout, "Done.\n");
114 }
115