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