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