xref: /openbsd-src/regress/lib/libssl/handshake/handshake_table.c (revision 8d6bcc7afa2f2190e3a864562b25e0f8c62b4ea8)
1 /*	$OpenBSD: handshake_table.c,v 1.4 2019/01/23 23:38:44 tb Exp $	*/
2 /*
3  * Copyright (c) 2019 Theo Buehler <tb@openbsd.org>
4  *
5  * Permission to use, copy, modify, and distribute this software for any
6  * purpose with or without fee is hereby granted, provided that the above
7  * copyright notice and this permission notice appear in all copies.
8  *
9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16  */
17 
18 #include <err.h>
19 #include <stdint.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <unistd.h>
23 
24 #include "tls13_handshake.h"
25 
26 /*
27  * From RFC 8446:
28  *
29  * Appendix A.  State Machine
30  *
31  *    This appendix provides a summary of the legal state transitions for
32  *    the client and server handshakes.  State names (in all capitals,
33  *    e.g., START) have no formal meaning but are provided for ease of
34  *    comprehension.  Actions which are taken only in certain circumstances
35  *    are indicated in [].  The notation "K_{send,recv} = foo" means "set
36  *    the send/recv key to the given key".
37  *
38  * A.1.  Client
39  *
40  *                               START <----+
41  *                Send ClientHello |        | Recv HelloRetryRequest
42  *           [K_send = early data] |        |
43  *                                 v        |
44  *            /                 WAIT_SH ----+
45  *            |                    | Recv ServerHello
46  *            |                    | K_recv = handshake
47  *        Can |                    V
48  *       send |                 WAIT_EE
49  *      early |                    | Recv EncryptedExtensions
50  *       data |           +--------+--------+
51  *            |     Using |                 | Using certificate
52  *            |       PSK |                 v
53  *            |           |            WAIT_CERT_CR
54  *            |           |        Recv |       | Recv CertificateRequest
55  *            |           | Certificate |       v
56  *            |           |             |    WAIT_CERT
57  *            |           |             |       | Recv Certificate
58  *            |           |             v       v
59  *            |           |              WAIT_CV
60  *            |           |                 | Recv CertificateVerify
61  *            |           +> WAIT_FINISHED <+
62  *            |                  | Recv Finished
63  *            \                  | [Send EndOfEarlyData]
64  *                               | K_send = handshake
65  *                               | [Send Certificate [+ CertificateVerify]]
66  *     Can send                  | Send Finished
67  *     app data   -->            | K_send = K_recv = application
68  *     after here                v
69  *                           CONNECTED
70  *
71  *    Note that with the transitions as shown above, clients may send
72  *    alerts that derive from post-ServerHello messages in the clear or
73  *    with the early data keys.  If clients need to send such alerts, they
74  *    SHOULD first rekey to the handshake keys if possible.
75  *
76  */
77 
78 struct child {
79 	enum tls13_message_type	mt;
80 	uint8_t			flag;
81 	uint8_t			forced;
82 	uint8_t			illegal;
83 };
84 
85 #define DEFAULT			0x00
86 
87 static struct child stateinfo[][TLS13_NUM_MESSAGE_TYPES] = {
88 	[CLIENT_HELLO] = {
89 		{SERVER_HELLO, NEGOTIATED, 0, 0},
90 	},
91 	[SERVER_HELLO] = {
92 		{SERVER_ENCRYPTED_EXTENSIONS, DEFAULT, 0, 0},
93 		{CLIENT_HELLO_RETRY, WITH_HRR, 0, 0},
94 	},
95 	[CLIENT_HELLO_RETRY] = {
96 		{SERVER_ENCRYPTED_EXTENSIONS, DEFAULT, 0, 0},
97 	},
98 	[SERVER_ENCRYPTED_EXTENSIONS] = {
99 		{SERVER_CERTIFICATE_REQUEST, DEFAULT, 0, 0},
100 		{SERVER_CERTIFICATE, WITHOUT_CR, 0, 0},
101 		{SERVER_FINISHED, WITH_PSK, 0, 0},
102 	},
103 	[SERVER_CERTIFICATE_REQUEST] = {
104 		{SERVER_CERTIFICATE, DEFAULT, 0, 0},
105 	},
106 	[SERVER_CERTIFICATE] = {
107 		{SERVER_CERTIFICATE_VERIFY, DEFAULT, 0, 0},
108 	},
109 	[SERVER_CERTIFICATE_VERIFY] = {
110 		{SERVER_FINISHED, DEFAULT, 0, 0},
111 	},
112 	[SERVER_FINISHED] = {
113 		{CLIENT_FINISHED, DEFAULT, WITHOUT_CR | WITH_PSK, 0},
114 		{CLIENT_CERTIFICATE, DEFAULT, 0, WITHOUT_CR | WITH_PSK},
115 		/* {CLIENT_END_OF_EARLY_DATA, WITH_0RTT, 0, 0}, */
116 	},
117 	[CLIENT_CERTIFICATE] = {
118 		{CLIENT_FINISHED, DEFAULT, 0, 0},
119 		{CLIENT_CERTIFICATE_VERIFY, WITH_CCV, 0, 0},
120 	},
121 	[CLIENT_CERTIFICATE_VERIFY] = {
122 		{CLIENT_FINISHED, DEFAULT, 0, 0},
123 	},
124 	[CLIENT_FINISHED] = {
125 		{APPLICATION_DATA, DEFAULT, 0, 0},
126 	},
127 	[APPLICATION_DATA] = {
128 		{0, DEFAULT, 0, 0},
129 	},
130 };
131 
132 void build_table(enum tls13_message_type
133     table[UINT8_MAX][TLS13_NUM_MESSAGE_TYPES], struct child current,
134     struct child end, struct child path[], uint8_t flags, unsigned int depth);
135 size_t count_handshakes(void);
136 const char *flag2str(uint8_t flag);
137 const char *mt2str(enum tls13_message_type mt);
138 void print_entry(enum tls13_message_type path[TLS13_NUM_MESSAGE_TYPES],
139     uint8_t flags);
140 void print_flags(uint8_t flags);
141 __dead void usage(void);
142 int verify_table(enum tls13_message_type
143     table[UINT8_MAX][TLS13_NUM_MESSAGE_TYPES], int print);
144 
145 const char *
146 flag2str(uint8_t flag)
147 {
148 	const char *ret;
149 
150 	if (flag & (flag - 1))
151 		errx(1, "more than one bit is set");
152 
153 	switch (flag) {
154 	case INITIAL:
155 		ret = "INITIAL";
156 		break;
157 	case NEGOTIATED:
158 		ret = "NEGOTIATED";
159 		break;
160 	case WITHOUT_CR:
161 		ret = "WITHOUT_CR";
162 		break;
163 	case WITH_HRR:
164 		ret = "WITH_HRR";
165 		break;
166 	case WITH_PSK:
167 		ret = "WITH_PSK";
168 		break;
169 	case WITH_CCV:
170 		ret = "WITH_CCV";
171 		break;
172 	case WITH_0RTT:
173 		ret = "WITH_0RTT";
174 		break;
175 	default:
176 		ret = "UNKNOWN";
177 	}
178 
179 	return ret;
180 }
181 
182 const char *
183 mt2str(enum tls13_message_type mt)
184 {
185 	const char *ret;
186 
187 	switch (mt) {
188 	case INVALID:
189 		ret = "INVALID";
190 		break;
191 	case CLIENT_HELLO:
192 		ret = "CLIENT_HELLO";
193 		break;
194 	case CLIENT_HELLO_RETRY:
195 		ret = "CLIENT_HELLO_RETRY";
196 		break;
197 	case CLIENT_END_OF_EARLY_DATA:
198 		ret = "CLIENT_END_OF_EARLY_DATA";
199 		break;
200 	case CLIENT_CERTIFICATE:
201 		ret = "CLIENT_CERTIFICATE";
202 		break;
203 	case CLIENT_CERTIFICATE_VERIFY:
204 		ret = "CLIENT_CERTIFICATE_VERIFY";
205 		break;
206 	case CLIENT_FINISHED:
207 		ret = "CLIENT_FINISHED";
208 		break;
209 	case CLIENT_KEY_UPDATE:
210 		ret = "CLIENT_KEY_UPDATE";
211 		break;
212 	case SERVER_HELLO:
213 		ret = "SERVER_HELLO";
214 		break;
215 	case SERVER_NEW_SESSION_TICKET:
216 		ret = "SERVER_NEW_SESSION_TICKET";
217 		break;
218 	case SERVER_ENCRYPTED_EXTENSIONS:
219 		ret = "SERVER_ENCRYPTED_EXTENSIONS";
220 		break;
221 	case SERVER_CERTIFICATE:
222 		ret = "SERVER_CERTIFICATE";
223 		break;
224 	case SERVER_CERTIFICATE_VERIFY:
225 		ret = "SERVER_CERTIFICATE_VERIFY";
226 		break;
227 	case SERVER_CERTIFICATE_REQUEST:
228 		ret = "SERVER_CERTIFICATE_REQUEST";
229 		break;
230 	case SERVER_FINISHED:
231 		ret = "SERVER_FINISHED";
232 		break;
233 	case APPLICATION_DATA:
234 		ret = "APPLICATION_DATA";
235 		break;
236 	case TLS13_NUM_MESSAGE_TYPES:
237 		ret = "TLS13_NUM_MESSAGE_TYPES";
238 		break;
239 	default:
240 		ret = "UNKNOWN";
241 		break;
242 	}
243 
244 	return ret;
245 }
246 
247 void
248 print_flags(uint8_t flags)
249 {
250 	int first = 1, i;
251 
252 	if (flags == 0) {
253 		printf("%s", flag2str(flags));
254 		return;
255 	}
256 
257 	for (i = 0; i < 8; i++) {
258 		uint8_t set = flags & (1U << i);
259 
260 		if (set) {
261 			printf("%s%s", first ? "" : " | ", flag2str(set));
262 			first = 0;
263 		}
264 	}
265 }
266 
267 void
268 print_entry(enum tls13_message_type path[TLS13_NUM_MESSAGE_TYPES],
269     uint8_t flags)
270 {
271 	int i;
272 
273 	printf("\t[");
274 	print_flags(flags);
275 	printf("] = {\n");
276 
277 	for (i = 0; i < TLS13_NUM_MESSAGE_TYPES; i++) {
278 		if (path[i] == 0)
279 			break;
280 		printf("\t\t%s,\n", mt2str(path[i]));
281 	}
282 	printf("\t},\n");
283 }
284 
285 extern enum tls13_message_type handshakes[][TLS13_NUM_MESSAGE_TYPES];
286 extern size_t handshake_count;
287 
288 size_t
289 count_handshakes(void)
290 {
291 	size_t	ret = 0, i;
292 
293 	for (i = 0; i < handshake_count; i++) {
294 		if (handshakes[i][0] != INVALID)
295 			ret++;
296 	}
297 
298 	return ret;
299 }
300 
301 void
302 build_table(enum tls13_message_type table[UINT8_MAX][TLS13_NUM_MESSAGE_TYPES],
303     struct child current, struct child end, struct child path[], uint8_t flags,
304     unsigned int depth)
305 {
306 	unsigned int i;
307 
308 	if (depth >= TLS13_NUM_MESSAGE_TYPES - 1)
309 		errx(1, "recursed too deeply");
310 
311 	/* Record current node. */
312 	path[depth++] = current;
313 	flags |= current.flag;
314 
315 	/* If we haven't reached the end, recurse over the children. */
316 	if (current.mt != end.mt) {
317 		for (i = 0; stateinfo[current.mt][i].mt != 0; i++) {
318 			struct child child = stateinfo[current.mt][i];
319 			int forced = stateinfo[current.mt][i].forced;
320 			int illegal = stateinfo[current.mt][i].illegal;
321 
322 			if ((forced == 0 || (forced & flags)) &&
323 			    (illegal == 0 || !(illegal & flags)))
324 				build_table(table, child, end, path, flags,
325 				    depth);
326 		}
327 		return;
328 	}
329 
330 	if (flags == 0)
331 		errx(1, "path does not set flags");
332 
333 	if (table[flags][0] != 0)
334 		errx(1, "path traversed twice");
335 
336 	for (i = 0; i < depth; i++)
337 		table[flags][i] = path[i].mt;
338 }
339 
340 int
341 verify_table(enum tls13_message_type table[UINT8_MAX][TLS13_NUM_MESSAGE_TYPES],
342     int print)
343 {
344 	int	success = 1, i;
345 	size_t	num_valid, num_found = 0;
346 	uint8_t	flags = 0;
347 
348 	do {
349 		if (table[flags][0] == 0)
350 			continue;
351 
352 		num_found++;
353 
354 		for (i = 0; i < TLS13_NUM_MESSAGE_TYPES; i++) {
355 			if (table[flags][i] != handshakes[flags][i]) {
356 				printf("incorrect entry %d of handshake ", i);
357 				print_flags(flags);
358 				printf("\n");
359 				success = 0;
360 			}
361 		}
362 
363 		if (print)
364 			print_entry(table[flags], flags);
365 	} while(++flags != 0);
366 
367 	num_valid = count_handshakes();
368 	if (num_valid != num_found) {
369 		printf("incorrect number of handshakes: want %zu, got %zu.\n",
370 		    num_valid, num_found);
371 		success = 0;
372 	}
373 
374 	return success;
375 }
376 
377 __dead void
378 usage(void)
379 {
380 	fprintf(stderr, "usage: handshake_table [-C]\n");
381 	exit(1);
382 }
383 
384 int
385 main(int argc, char *argv[])
386 {
387 	static enum tls13_message_type
388 	    hs_table[UINT8_MAX][TLS13_NUM_MESSAGE_TYPES] = {
389 		[INITIAL] = {
390 			CLIENT_HELLO,
391 			SERVER_HELLO,
392 		},
393 	};
394 	struct child	start = {
395 		CLIENT_HELLO, NEGOTIATED, 0, 0,
396 	};
397 	struct child	end = {
398 		APPLICATION_DATA, DEFAULT, 0, 0,
399 	};
400 	struct child	path[TLS13_NUM_MESSAGE_TYPES] = {{0}};
401 	uint8_t		flags = 0;
402 	unsigned int	depth = 0;
403 	int		ch, print = 0;
404 
405 	while ((ch = getopt(argc, argv, "C")) != -1) {
406 		switch (ch) {
407 		case 'C':
408 			print = 1;
409 			break;
410 		default:
411 			usage();
412 		}
413 	}
414 	argc -= optind;
415 	argv += optind;
416 
417 	if (argc != 0)
418 		usage();
419 
420 	build_table(hs_table, start, end, path, flags, depth);
421 	if (!verify_table(hs_table, print))
422 		return 1;
423 
424 	if (!print)
425 		printf("SUCCESS\n");
426 
427 	return 0;
428 }
429