1 /*
2  * Copyright (C) 2012-2016 Sean Buckheister
3  * Copyright (C) 2016 Nikos Mavrogiannopoulos
4  * Copyright (C) 2016 Red Hat, Inc.
5  *
6  * This file is part of GnuTLS.
7  *
8  * GnuTLS is free software; you can redistribute it and/or modify it
9  * under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * GnuTLS is distributed in the hope that it will be useful, but
14  * WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with GnuTLS; if not, write to the Free Software Foundation,
20  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21  */
22 
23 /*
24  * DTLS stress test utility
25  *
26  * **** Available parameters ****
27  *
28  *	-nb		 enable nonblocking operations on sessions
29  *	-batch	      read test identifiers from stdin and run them
30  *	-d		  increase debug level by one
31  *	-r		  replay messages (very crude replay mechanism)
32  *	-d <n>	      set debug level to <n>
33  *	-die		don't start new tests after the first detected failure
34  *	-timeout <n>	set handshake timeout to <n> seconds. Tests that don't make progress
35  *			    within twice this time will be forcibly killed. (default: 120)
36  *	-retransmit <n>     set retransmit timeout to <n> milliseconds (default: 100)
37  *	-j <n>	      run up to <n> tests in parallel
38  *	-full	       use full handshake with mutual certificate authentication
39  *	-resume	     use resumed handshake
40  *	-shello <perm>      run only one test, with the server hello flight permuted as <perm>
41  *	-sfinished <perm>   run only one test, with the server finished flight permuted as <perm>
42  *	-cfinished <perm>   run only one test, with the client finished flight permuted as <perm>
43  *	<packet name>       run only one test, drop <packet name> three times
44  *			    valid values for <packet name> are:
45  *				SHello, SCertificate, SKeyExchange, SCertificateRequest, SHelloDone,
46  *				CCertificate, CKeyExchange, CCertificateVerify, CChangeCipherSpec,
47  *				CFinished, SChangeCipherSpec, SFinished
48  *			    using *Certificate* without -full will yield unexpected results
49  *
50  *
51  * **** Permutation handling ****
52  *
53  * Flight length for -sfinished is 2, for -shello and -cfinished they are 5 with -full, 3 otherwise.
54  * Permutations are given with base 0 and specify the order in which reordered packets are transmitted.
55  * For example, -full -shello 42130 will transmit server hello flight packets in the order
56  * SHelloDone, SKeyExchange, SCertificate, SCertificateRequest, SHello
57  *
58  * When -resume is specified the -sfinished flight length is 3 (same as shello), cfinished is 2.
59  * The -resume option has to be combined with sfinished or cfinished.
60  *
61  * **** Output format ****
62  *
63  * Every line printed for any given test is prefixed by a unique id for that test. See run_test_by_id for
64  * exact composition. Errors encountered during execution are printed, with one status line after test
65  * completen. The format for this line is as follows:
66  *
67  * <id> <status> SHello(<shperm>), SFinished(<sfinperm>), CFinished(<cfinperm>) :- <drops>
68  *
69  * The format for error lines is <id> <role>| <text>, with <role> being the role of the child process
70  * that encountered the error, and <text> being obvious.
71  *
72  * <id> is the unique id for the test, it can be used as input to -batch.
73  * <status> can be ++ for a successful test, -- for a failure, TT for a deadlock timeout killed test,
74  *     or !! for a test has died due to some unforeseen circumstances like syscall failures.
75  * <shperm>, <sfinperm>, <cfinperm> show the permutation for the respective flights used.
76  *    They can be used as input to -shello, -sfinished, and -cfinished, respectively.
77  * <drops> is a comma separated list of <packet name>, one for every packet dropped thrice
78  *
79  *
80  * **** Exit status ****
81  *
82  * 0    all tests have passed
83  * 1    some tests have failed
84  * 4    the master processed has encountered unexpected errors
85  * 8    error parsing command line
86  */
87 
88 #include <config.h>
89 #include <gnutls/gnutls.h>
90 #include <gnutls/openpgp.h>
91 #include <gnutls/dtls.h>
92 #include <unistd.h>
93 #include "../utils.h"
94 #include <sys/socket.h>
95 #include <sys/types.h>
96 #include <netinet/in.h>
97 #include <fcntl.h>
98 #include <stdio.h>
99 #include <stdlib.h>
100 #include <string.h>
101 #include <errno.h>
102 #include <poll.h>
103 #include <time.h>
104 #include <assert.h>
105 #include <sys/wait.h>
106 
107 #if _POSIX_TIMERS && (_POSIX_TIMERS - 200112L) >= 0
108 
109 // {{{ types
110 
111 #define log(fmt, ...) \
112 	if (debug) fprintf(stdout, "%i %s| "fmt, run_id, role_name, ##__VA_ARGS__)
113 
114 typedef struct {
115 	int count;
116 } filter_packet_state_t;
117 
118 typedef struct {
119 	const char *name;
120 	gnutls_datum_t packets[5];
121 	int *order;
122 	int count;
123 } filter_permute_state_t;
124 
125 typedef void (*filter_fn) (gnutls_transport_ptr_t, const unsigned char *,
126 			   size_t);
127 
128 typedef int (*match_fn) (const unsigned char *, size_t);
129 
130 enum role { SERVER, CLIENT };
131 
132 // }}}
133 
134 // {{{ static data
135 
136 static int permutations2[2][2]
137 = { {0, 1}, {1, 0} };
138 
139 static const char *permutation_names2[]
140 = { "01", "10", 0 };
141 
142 static int permutations3[6][3]
143 = { {0, 1, 2}, {0, 2, 1}, {1, 0, 2}, {1, 2, 0}, {2, 0, 1}, {2, 1, 0} };
144 
145 static const char *permutation_names3[]
146 = { "012", "021", "102", "120", "201", "210", 0 };
147 
148 static int permutations5[120][5] = {
149 	{0, 1, 2, 3, 4}, {0, 2, 1, 3, 4}, {1, 0, 2, 3, 4}, {1, 2, 0, 3, 4},
150 	{2, 0, 1, 3, 4}, {2, 1, 0, 3, 4}, {0, 1, 3, 2, 4}, {0, 2, 3, 1, 4},
151 	{1, 0, 3, 2, 4}, {1, 2, 3, 0, 4}, {2, 0, 3, 1, 4}, {2, 1, 3, 0, 4},
152 	{0, 3, 1, 2, 4}, {0, 3, 2, 1, 4}, {1, 3, 0, 2, 4}, {1, 3, 2, 0, 4},
153 	{2, 3, 0, 1, 4}, {2, 3, 1, 0, 4}, {3, 0, 1, 2, 4}, {3, 0, 2, 1, 4},
154 	{3, 1, 0, 2, 4}, {3, 1, 2, 0, 4}, {3, 2, 0, 1, 4}, {3, 2, 1, 0, 4},
155 	{0, 1, 2, 4, 3}, {0, 2, 1, 4, 3}, {1, 0, 2, 4, 3}, {1, 2, 0, 4, 3},
156 	{2, 0, 1, 4, 3}, {2, 1, 0, 4, 3}, {0, 1, 3, 4, 2}, {0, 2, 3, 4, 1},
157 	{1, 0, 3, 4, 2}, {1, 2, 3, 4, 0}, {2, 0, 3, 4, 1}, {2, 1, 3, 4, 0},
158 	{0, 3, 1, 4, 2}, {0, 3, 2, 4, 1}, {1, 3, 0, 4, 2}, {1, 3, 2, 4, 0},
159 	{2, 3, 0, 4, 1}, {2, 3, 1, 4, 0}, {3, 0, 1, 4, 2}, {3, 0, 2, 4, 1},
160 	{3, 1, 0, 4, 2}, {3, 1, 2, 4, 0}, {3, 2, 0, 4, 1}, {3, 2, 1, 4, 0},
161 	{0, 1, 4, 2, 3}, {0, 2, 4, 1, 3}, {1, 0, 4, 2, 3}, {1, 2, 4, 0, 3},
162 	{2, 0, 4, 1, 3}, {2, 1, 4, 0, 3}, {0, 1, 4, 3, 2}, {0, 2, 4, 3, 1},
163 	{1, 0, 4, 3, 2}, {1, 2, 4, 3, 0}, {2, 0, 4, 3, 1}, {2, 1, 4, 3, 0},
164 	{0, 3, 4, 1, 2}, {0, 3, 4, 2, 1}, {1, 3, 4, 0, 2}, {1, 3, 4, 2, 0},
165 	{2, 3, 4, 0, 1}, {2, 3, 4, 1, 0}, {3, 0, 4, 1, 2}, {3, 0, 4, 2, 1},
166 	{3, 1, 4, 0, 2}, {3, 1, 4, 2, 0}, {3, 2, 4, 0, 1}, {3, 2, 4, 1, 0},
167 	{0, 4, 1, 2, 3}, {0, 4, 2, 1, 3}, {1, 4, 0, 2, 3}, {1, 4, 2, 0, 3},
168 	{2, 4, 0, 1, 3}, {2, 4, 1, 0, 3}, {0, 4, 1, 3, 2}, {0, 4, 2, 3, 1},
169 	{1, 4, 0, 3, 2}, {1, 4, 2, 3, 0}, {2, 4, 0, 3, 1}, {2, 4, 1, 3, 0},
170 	{0, 4, 3, 1, 2}, {0, 4, 3, 2, 1}, {1, 4, 3, 0, 2}, {1, 4, 3, 2, 0},
171 	{2, 4, 3, 0, 1}, {2, 4, 3, 1, 0}, {3, 4, 0, 1, 2}, {3, 4, 0, 2, 1},
172 	{3, 4, 1, 0, 2}, {3, 4, 1, 2, 0}, {3, 4, 2, 0, 1}, {3, 4, 2, 1, 0},
173 	{4, 0, 1, 2, 3}, {4, 0, 2, 1, 3}, {4, 1, 0, 2, 3}, {4, 1, 2, 0, 3},
174 	{4, 2, 0, 1, 3}, {4, 2, 1, 0, 3}, {4, 0, 1, 3, 2}, {4, 0, 2, 3, 1},
175 	{4, 1, 0, 3, 2}, {4, 1, 2, 3, 0}, {4, 2, 0, 3, 1}, {4, 2, 1, 3, 0},
176 	{4, 0, 3, 1, 2}, {4, 0, 3, 2, 1}, {4, 1, 3, 0, 2}, {4, 1, 3, 2, 0},
177 	{4, 2, 3, 0, 1}, {4, 2, 3, 1, 0}, {4, 3, 0, 1, 2}, {4, 3, 0, 2, 1},
178 	{4, 3, 1, 0, 2}, {4, 3, 1, 2, 0}, {4, 3, 2, 0, 1}, {4, 3, 2, 1, 0}
179 };
180 
181 static const char *permutation_names5[]
182     = { "01234", "02134", "10234", "12034", "20134", "21034", "01324",
183 	"02314", "10324", "12304", "20314", "21304", "03124", "03214",
184 	"13024", "13204", "23014", "23104", "30124", "30214", "31024",
185 	"31204", "32014", "32104", "01243", "02143", "10243", "12043",
186 	"20143", "21043", "01342", "02341", "10342", "12340", "20341",
187 	"21340", "03142", "03241", "13042", "13240", "23041", "23140",
188 	"30142", "30241", "31042", "31240", "32041", "32140", "01423",
189 	"02413", "10423", "12403", "20413", "21403", "01432", "02431",
190 	"10432", "12430", "20431", "21430", "03412", "03421", "13402",
191 	"13420", "23401", "23410", "30412", "30421", "31402", "31420",
192 	"32401", "32410", "04123", "04213", "14023", "14203", "24013",
193 	"24103", "04132", "04231", "14032", "14230", "24031", "24130",
194 	"04312", "04321", "14302", "14320", "24301", "24310", "34012",
195 	"34021", "34102", "34120", "34201", "34210", "40123", "40213",
196 	"41023", "41203", "42013", "42103", "40132", "40231", "41032",
197 	"41230", "42031", "42130", "40312", "40321", "41302", "41320",
198 	"42301", "42310", "43012", "43021", "43102", "43120", "43201",
199 	"43210", 0
200 };
201 
202 static const char *filter_names[8]
203     = { "SHello",
204 	"SKeyExchange",
205 	"SHelloDone",
206 	"CKeyExchange",
207 	"CChangeCipherSpec",
208 	"CFinished",
209 	"SChangeCipherSpec",
210 	"SFinished"
211 };
212 
213 static const char *filter_names_resume[]
214     = { "SHello",
215 	"SChangeCipherSpec",
216 	"SFinished",
217 	"CChangeCipherSpec",
218 	"CFinished"
219 };
220 
221 static const char *filter_names_full[12]
222     = { "SHello",
223 	"SCertificate",
224 	"SKeyExchange",
225 	"SCertificateRequest",
226 	"SHelloDone",
227 	"CCertificate",
228 	"CKeyExchange",
229 	"CCertificateVerify",
230 	"CChangeCipherSpec",
231 	"CFinished",
232 	"SChangeCipherSpec",
233 	"SFinished"
234 };
235 
236 #include "cert-common.h"
237 
238 // }}}
239 
240 // {{{ other global state
241 
242 enum role role;
243 
244 #define role_name (role == SERVER ? "server" : "client")
245 
246 int debug;
247 int nonblock;
248 int replay;
249 int full;
250 int resume;
251 int timeout_seconds;
252 int retransmit_milliseconds;
253 int run_to_end;
254 
255 int run_id;
256 
257 // }}}
258 
259 // {{{ logging and error handling
260 
logfn(int level,const char * s)261 static void logfn(int level, const char *s)
262 {
263 	if (debug) {
264 		fprintf(stdout, "%i %s|<%i> %s", run_id, role_name, level, s);
265 	}
266 }
267 
auditfn(gnutls_session_t session,const char * s)268 static void auditfn(gnutls_session_t session, const char *s)
269 {
270 	if (debug) {
271 		fprintf(stdout, "%i %s| %s", run_id, role_name, s);
272 	}
273 }
274 
drop(const char * packet)275 static void drop(const char *packet)
276 {
277 	if (debug) {
278 		log("dropping %s\n", packet);
279 	}
280 }
281 
_process_error(int loc,int code,int die)282 static int _process_error(int loc, int code, int die)
283 {
284 	if (code < 0 && (die || code != GNUTLS_E_AGAIN)) {
285 		fprintf(stdout, "%i <%s tls> line %i: %s", run_id,
286 			role_name, loc, gnutls_strerror(code));
287 		if (gnutls_error_is_fatal(code) || die) {
288 			fprintf(stdout, " (fatal)\n");
289 			exit(1);
290 		} else {
291 			fprintf(stdout, "\n");
292 		}
293 	}
294 	return code;
295 }
296 
297 #define die_on_error(code) _process_error(__LINE__, code, 1)
298 #define process_error(code) _process_error(__LINE__, code, 0)
299 
_process_error_or_timeout(int loc,int err,time_t tdiff)300 static void _process_error_or_timeout(int loc, int err, time_t tdiff)
301 {
302 	if (err < 0) {
303 		if (err != GNUTLS_E_TIMEDOUT || tdiff >= 60) {
304 			_process_error(loc, err, 0);
305 		} else {
306 			log("line %i: {spurious timeout} (fatal)", loc);
307 			exit(1);
308 		}
309 	}
310 }
311 
312 #define process_error_or_timeout(code, tdiff) _process_error_or_timeout(__LINE__, code, tdiff)
313 
rperror(const char * name)314 static void rperror(const char *name)
315 {
316 	fprintf(stdout, "%i %s| %s\n", run_id, role_name, name);
317 }
318 
319 // }}}
320 
321 // {{{ init, shared, and teardown code and data for packet stream filters
322 
323 filter_packet_state_t state_packet_ServerHello = { 0 };
324 filter_packet_state_t state_packet_ServerCertificate = { 0 };
325 filter_packet_state_t state_packet_ServerKeyExchange = { 0 };
326 filter_packet_state_t state_packet_ServerCertificateRequest = { 0 };
327 filter_packet_state_t state_packet_ServerHelloDone = { 0 };
328 filter_packet_state_t state_packet_ClientCertificate = { 0 };
329 filter_packet_state_t state_packet_ClientKeyExchange = { 0 };
330 filter_packet_state_t state_packet_ClientCertificateVerify = { 0 };
331 filter_packet_state_t state_packet_ClientChangeCipherSpec = { 0 };
332 filter_packet_state_t state_packet_ClientFinished = { 0 };
333 filter_packet_state_t state_packet_ClientFinishedResume = { 0 };
334 filter_packet_state_t state_packet_ServerChangeCipherSpec = { 0 };
335 filter_packet_state_t state_packet_ServerFinished = { 0 };
336 filter_packet_state_t state_packet_ServerFinishedResume = { 0 };
337 
338 static filter_permute_state_t state_permute_ServerHello =
339     { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
340 static filter_permute_state_t state_permute_ServerHelloFull =
341     { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
342 static filter_permute_state_t state_permute_ServerFinished =
343     { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
344 static filter_permute_state_t state_permute_ServerFinishedResume =
345     { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
346 static filter_permute_state_t state_permute_ClientFinished =
347     { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
348 static filter_permute_state_t state_permute_ClientFinishedResume =
349     { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
350 static filter_permute_state_t state_permute_ClientFinishedFull =
351     { 0, {{0, 0}, {0, 0}, {0, 0}, {0, 0}, {0, 0}}, 0, 0 };
352 
353 filter_fn filter_chain[32];
354 int filter_current_idx;
355 
filter_permute_state_free_buffer(filter_permute_state_t * state)356 static void filter_permute_state_free_buffer(filter_permute_state_t * state)
357 {
358 	unsigned int i;
359 
360 	for (i = 0; i < sizeof(state->packets) / sizeof(state->packets[0]); i++) {
361 		free(state->packets[i].data);
362 		state->packets[i].data = NULL;
363 	}
364 }
365 
filter_clear_state(void)366 static void filter_clear_state(void)
367 {
368 	filter_current_idx = 0;
369 
370 	filter_permute_state_free_buffer(&state_permute_ServerHello);
371 	filter_permute_state_free_buffer(&state_permute_ServerHelloFull);
372 	filter_permute_state_free_buffer(&state_permute_ServerFinished);
373 	filter_permute_state_free_buffer(&state_permute_ServerFinishedResume);
374 	filter_permute_state_free_buffer(&state_permute_ClientFinished);
375 	filter_permute_state_free_buffer(&state_permute_ClientFinishedResume);
376 	filter_permute_state_free_buffer(&state_permute_ClientFinishedFull);
377 
378 	memset(&state_packet_ServerHello, 0, sizeof(state_packet_ServerHello));
379 	memset(&state_packet_ServerCertificate, 0,
380 	       sizeof(state_packet_ServerCertificate));
381 	memset(&state_packet_ServerKeyExchange, 0,
382 	       sizeof(state_packet_ServerKeyExchange));
383 	memset(&state_packet_ServerCertificateRequest, 0,
384 	       sizeof(state_packet_ServerCertificateRequest));
385 	memset(&state_packet_ServerHelloDone, 0,
386 	       sizeof(state_packet_ServerHelloDone));
387 	memset(&state_packet_ClientCertificate, 0,
388 	       sizeof(state_packet_ClientCertificate));
389 	memset(&state_packet_ClientKeyExchange, 0,
390 	       sizeof(state_packet_ClientKeyExchange));
391 	memset(&state_packet_ClientCertificateVerify, 0,
392 	       sizeof(state_packet_ClientCertificateVerify));
393 	memset(&state_packet_ClientChangeCipherSpec, 0,
394 	       sizeof(state_packet_ClientChangeCipherSpec));
395 	memset(&state_packet_ClientFinished, 0,
396 	       sizeof(state_packet_ClientFinished));
397 	memset(&state_packet_ClientFinishedResume, 0,
398 	       sizeof(state_packet_ClientFinishedResume));
399 	memset(&state_packet_ServerChangeCipherSpec, 0,
400 	       sizeof(state_packet_ServerChangeCipherSpec));
401 	memset(&state_packet_ServerFinished, 0,
402 	       sizeof(state_packet_ServerFinished));
403 	memset(&state_packet_ServerFinishedResume, 0,
404 	       sizeof(state_packet_ServerFinishedResume));
405 	memset(&state_permute_ServerHello, 0,
406 	       sizeof(state_permute_ServerHello));
407 	memset(&state_permute_ServerHelloFull, 0,
408 	       sizeof(state_permute_ServerHelloFull));
409 	memset(&state_permute_ServerFinished, 0,
410 	       sizeof(state_permute_ServerFinished));
411 	memset(&state_permute_ClientFinished, 0,
412 	       sizeof(state_permute_ClientFinished));
413 	memset(&state_permute_ClientFinishedResume, 0,
414 	       sizeof(state_permute_ClientFinishedResume));
415 	memset(&state_permute_ClientFinishedFull, 0,
416 	       sizeof(state_permute_ClientFinishedFull));
417 
418 	state_permute_ServerHello.name = "ServerHello";
419 	state_permute_ServerHelloFull.name = "ServerHelloFull";
420 	state_permute_ServerFinished.name = "ServerFinished";
421 	state_permute_ServerFinishedResume.name = "ServerFinishedResume";
422 	state_permute_ClientFinished.name = "ClientFinished";
423 	state_permute_ClientFinishedResume.name = "ClientFinishedResume";
424 	state_permute_ClientFinishedFull.name = "ClientFinishedFull";
425 }
426 
427 /* replay buffer */
428 static int rbuffer[5 * 1024];
429 unsigned rbuffer_size = 0;
430 
filter_run_next(gnutls_transport_ptr_t fd,const unsigned char * buffer,size_t len)431 static void filter_run_next(gnutls_transport_ptr_t fd,
432 			    const unsigned char *buffer, size_t len)
433 {
434 	int ret = 0;
435 	filter_fn fn = filter_chain[filter_current_idx];
436 	filter_current_idx++;
437 	if (fn) {
438 		fn(fd, buffer, len);
439 	} else {
440 		ret = send((int)(intptr_t) fd, buffer, len, 0);
441 	}
442 	filter_current_idx--;
443 
444 	if (ret > 0 && replay != 0) {
445 		if (rbuffer_size == 0 && len < sizeof(rbuffer)) {
446 			memcpy(rbuffer, buffer, len);
447 			rbuffer_size = len;
448 		} else if (rbuffer_size != 0) {
449 			send((int)(intptr_t) fd, rbuffer, rbuffer_size, 0);
450 			if (len < sizeof(rbuffer) && len > rbuffer_size) {
451 				memcpy(rbuffer, buffer, len);
452 				rbuffer_size = len;
453 			}
454 		}
455 	}
456 }
457 
458 // }}}
459 
460 // {{{ packet match functions
461 
match_ServerHello(const unsigned char * buffer,size_t len)462 static int match_ServerHello(const unsigned char *buffer, size_t len)
463 {
464 	return role == SERVER && len >= 13 + 1 && buffer[0] == 22
465 	    && buffer[13] == 2;
466 }
467 
match_ServerCertificate(const unsigned char * buffer,size_t len)468 static int match_ServerCertificate(const unsigned char *buffer, size_t len)
469 {
470 	return role == SERVER && len >= 13 + 1 && buffer[0] == 22
471 	    && buffer[13] == 11;
472 }
473 
match_ServerKeyExchange(const unsigned char * buffer,size_t len)474 static int match_ServerKeyExchange(const unsigned char *buffer, size_t len)
475 {
476 	return role == SERVER && len >= 13 + 1 && buffer[0] == 22
477 	    && buffer[13] == 12;
478 }
479 
match_ServerCertificateRequest(const unsigned char * buffer,size_t len)480 static int match_ServerCertificateRequest(const unsigned char *buffer,
481 					  size_t len)
482 {
483 	return role == SERVER && len >= 13 + 1 && buffer[0] == 22
484 	    && buffer[13] == 13;
485 }
486 
match_ServerHelloDone(const unsigned char * buffer,size_t len)487 static int match_ServerHelloDone(const unsigned char *buffer, size_t len)
488 {
489 	return role == SERVER && len >= 13 + 1 && buffer[0] == 22
490 	    && buffer[13] == 14;
491 }
492 
match_ClientCertificate(const unsigned char * buffer,size_t len)493 static int match_ClientCertificate(const unsigned char *buffer, size_t len)
494 {
495 	return role == CLIENT && len >= 13 + 1 && buffer[0] == 22
496 	    && buffer[13] == 11;
497 }
498 
match_ClientKeyExchange(const unsigned char * buffer,size_t len)499 static int match_ClientKeyExchange(const unsigned char *buffer, size_t len)
500 {
501 	return role == CLIENT && len >= 13 + 1 && buffer[0] == 22
502 	    && buffer[13] == 16;
503 }
504 
match_ClientCertificateVerify(const unsigned char * buffer,size_t len)505 static int match_ClientCertificateVerify(const unsigned char *buffer,
506 					 size_t len)
507 {
508 	return role == CLIENT && len >= 13 + 1 && buffer[0] == 22
509 	    && buffer[13] == 15;
510 }
511 
match_ClientChangeCipherSpec(const unsigned char * buffer,size_t len)512 static int match_ClientChangeCipherSpec(const unsigned char *buffer, size_t len)
513 {
514 	return role == CLIENT && len >= 13 && buffer[0] == 20;
515 }
516 
match_ClientFinished(const unsigned char * buffer,size_t len)517 static int match_ClientFinished(const unsigned char *buffer, size_t len)
518 {
519 	return role == CLIENT && len >= 13 && buffer[0] == 22 && buffer[4] == 1;
520 }
521 
match_ServerChangeCipherSpec(const unsigned char * buffer,size_t len)522 static int match_ServerChangeCipherSpec(const unsigned char *buffer, size_t len)
523 {
524 	return role == SERVER && len >= 13 && buffer[0] == 20;
525 }
526 
match_ServerFinished(const unsigned char * buffer,size_t len)527 static int match_ServerFinished(const unsigned char *buffer, size_t len)
528 {
529 	return role == SERVER && len >= 13 && buffer[0] == 22 && buffer[4] == 1;
530 }
531 
532 // }}}
533 
534 // {{{ packet drop filters
535 
536 #define FILTER_DROP_COUNT 3
537 #define DECLARE_FILTER(packet) \
538 	static void filter_packet_##packet(gnutls_transport_ptr_t fd, \
539 			const unsigned char* buffer, size_t len) \
540 	{ \
541 		if (match_##packet(buffer, len) && (state_packet_##packet).count++ < FILTER_DROP_COUNT) { \
542 			drop(#packet); \
543 		} else { \
544 			filter_run_next(fd, buffer, len); \
545 		} \
546 	}
547 
548 DECLARE_FILTER(ServerHello)
DECLARE_FILTER(ServerCertificate)549     DECLARE_FILTER(ServerCertificate)
550     DECLARE_FILTER(ServerKeyExchange)
551     DECLARE_FILTER(ServerCertificateRequest)
552     DECLARE_FILTER(ServerHelloDone)
553     DECLARE_FILTER(ClientCertificate)
554     DECLARE_FILTER(ClientKeyExchange)
555     DECLARE_FILTER(ClientCertificateVerify)
556     DECLARE_FILTER(ClientChangeCipherSpec)
557     DECLARE_FILTER(ClientFinished)
558     DECLARE_FILTER(ServerChangeCipherSpec)
559     DECLARE_FILTER(ServerFinished)
560 // }}}
561 // {{{ flight permutation filters
562 static void filter_permute_state_run(filter_permute_state_t * state,
563 				     int packetCount,
564 				     gnutls_transport_ptr_t fd,
565 				     const unsigned char *buffer, size_t len)
566 {
567 	unsigned char *data = malloc(len);
568 	int packet = state->order[state->count];
569 
570 	if (debug > 2)
571 		log("running permutation for %s/%d/%d\n", state->name, packetCount, state->count);
572 
573 	memcpy(data, buffer, len);
574 	state->packets[packet].data = data;
575 	state->packets[packet].size = len;
576 	state->count++;
577 
578 	if (state->count == packetCount) {
579 		for (packet = 0; packet < packetCount; packet++) {
580 			filter_run_next(fd, state->packets[packet].data,
581 					state->packets[packet].size);
582 		}
583 		filter_permute_state_free_buffer(state);
584 		state->count = 0;
585 	}
586 }
587 
588 #define DECLARE_PERMUTE(flight) \
589 	static void filter_permute_##flight(gnutls_transport_ptr_t fd, \
590 			const unsigned char* buffer, size_t len) \
591 	{ \
592 		int count = sizeof(permute_match_##flight) / sizeof(permute_match_##flight[0]); \
593 		int i; \
594 		for (i = 0; i < count; i++) { \
595 			if (permute_match_##flight[i](buffer, len)) { \
596 				filter_permute_state_run(&state_permute_##flight, count, fd, buffer, len); \
597 				return; \
598 			} \
599 		} \
600 		filter_run_next(fd, buffer, len); \
601 	}
602 
603 static match_fn permute_match_ServerHello[] =
604     { match_ServerHello, match_ServerKeyExchange, match_ServerHelloDone };
605 
606 static match_fn permute_match_ServerHelloFull[] =
607     { match_ServerHello, match_ServerCertificate, match_ServerKeyExchange,
608 	match_ServerCertificateRequest, match_ServerHelloDone
609 };
610 
611 static match_fn permute_match_ServerFinished[] =
612     { match_ServerChangeCipherSpec, match_ServerFinished };
613 
614 static match_fn permute_match_ServerFinishedResume[] =
615     { match_ServerHello, match_ServerChangeCipherSpec, match_ServerFinished };
616 
617 static match_fn permute_match_ClientFinished[] =
618     { match_ClientKeyExchange, match_ClientChangeCipherSpec,
619 	match_ClientFinished
620 };
621 
622 static match_fn permute_match_ClientFinishedResume[] =
623     { match_ClientChangeCipherSpec, match_ClientFinished
624 };
625 
626 static match_fn permute_match_ClientFinishedFull[] =
627     { match_ClientCertificate, match_ClientKeyExchange,
628 	match_ClientCertificateVerify, match_ClientChangeCipherSpec,
629 	match_ClientFinished
630 };
631 
632 DECLARE_PERMUTE(ServerHello)
633     DECLARE_PERMUTE(ServerHelloFull)
634     DECLARE_PERMUTE(ServerFinishedResume)
635     DECLARE_PERMUTE(ServerFinished)
636     DECLARE_PERMUTE(ClientFinished)
637     DECLARE_PERMUTE(ClientFinishedResume)
638     DECLARE_PERMUTE(ClientFinishedFull)
639 // }}}
640 // {{{ emergency deadlock resolution time bomb
641 timer_t killtimer_tid = 0;
642 
killtimer_set(void)643 static void killtimer_set(void)
644 {
645 	struct sigevent sig;
646 	struct itimerspec tout = { {0, 0}, {2 * timeout_seconds, 0} };
647 
648 	if (killtimer_tid != 0) {
649 		timer_delete(killtimer_tid);
650 	}
651 
652 	memset(&sig, 0, sizeof(sig));
653 	sig.sigev_notify = SIGEV_SIGNAL;
654 	sig.sigev_signo = 15;
655 	if (timer_create(CLOCK_MONOTONIC, &sig, &killtimer_tid) < 0) {
656 		rperror("timer_create");
657 		exit(3);
658 	}
659 
660 	timer_settime(killtimer_tid, 0, &tout, 0);
661 }
662 
663 // }}}
664 
665 // {{{ actual gnutls operations
666 
667 gnutls_certificate_credentials_t cred;
668 gnutls_session_t session;
669 
writefn(gnutls_transport_ptr_t fd,const void * buffer,size_t len)670 static ssize_t writefn(gnutls_transport_ptr_t fd, const void *buffer,
671 		       size_t len)
672 {
673 	filter_run_next(fd, (const unsigned char *)buffer, len);
674 	return len;
675 }
676 
await(int fd,int timeout)677 static void await(int fd, int timeout)
678 {
679 	if (nonblock) {
680 		struct pollfd p = { fd, POLLIN, 0 };
681 		if (poll(&p, 1, timeout) < 0 && errno != EAGAIN
682 		    && errno != EINTR) {
683 			rperror("poll");
684 			exit(3);
685 		}
686 	}
687 }
688 
cred_init(void)689 static void cred_init(void)
690 {
691 	assert(gnutls_certificate_allocate_credentials(&cred)>=0);
692 
693 	gnutls_certificate_set_x509_key_mem(cred, &cli_ca3_cert, &cli_ca3_key,
694 					       GNUTLS_X509_FMT_PEM);
695 }
696 
session_init(int sock,int server)697 static void session_init(int sock, int server)
698 {
699 	gnutls_init(&session,
700 		    GNUTLS_DATAGRAM | (server ? GNUTLS_SERVER : GNUTLS_CLIENT)
701 		    | GNUTLS_NONBLOCK * nonblock);
702 	gnutls_priority_set_direct(session,
703 				   "NORMAL:+ECDHE-RSA:+ANON-ECDH",
704 				   0);
705 	gnutls_transport_set_int(session, sock);
706 
707 	if (full) {
708 		gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE, cred);
709 		if (server) {
710 			gnutls_certificate_server_set_request(session,
711 							      GNUTLS_CERT_REQUIRE);
712 		}
713 	} else if (server) {
714 		gnutls_anon_server_credentials_t acred;
715 		assert(gnutls_anon_allocate_server_credentials(&acred)>=0);
716 		gnutls_credentials_set(session, GNUTLS_CRD_ANON, acred);
717 	} else {
718 		gnutls_anon_client_credentials_t acred;
719 		assert(gnutls_anon_allocate_client_credentials(&acred)>=0);
720 		gnutls_credentials_set(session, GNUTLS_CRD_ANON, acred);
721 	}
722 
723 	gnutls_dtls_set_mtu(session, 1400);
724 	gnutls_dtls_set_timeouts(session, retransmit_milliseconds,
725 				 timeout_seconds * 1000);
726 }
727 
client(int sock)728 static void client(int sock)
729 {
730 	int err = 0;
731 	time_t started = time(0);
732 	const char *line = "foobar!";
733 	char buffer[8192];
734 	int len, ret;
735 	gnutls_datum_t data = {NULL, 0};
736 
737 	session_init(sock, 0);
738 
739 	killtimer_set();
740 
741 	if (resume) {
742 		do {
743 			err = process_error(gnutls_handshake(session));
744 			if (err != 0) {
745 				int t = gnutls_dtls_get_timeout(session);
746 				await(sock, t ? t : 100);
747 			}
748 		} while (err != 0);
749 		process_error_or_timeout(err, time(0) - started);
750 
751 		ret = gnutls_session_get_data2(session, &data);
752 		if (ret < 0) {
753 			exit(1);
754 		}
755 		gnutls_deinit(session);
756 
757 		session_init(sock, 0);
758 		gnutls_session_set_data(session, data.data, data.size);
759 		gnutls_free(data.data);
760 		data.data = NULL;
761 
762 		if (debug) {
763 			fprintf(stdout, "%i %s| initial handshake complete\n", run_id, role_name);
764 		}
765 	}
766 
767 	gnutls_transport_set_push_function(session, writefn);
768 
769 	killtimer_set();
770 	do {
771 		err = process_error(gnutls_handshake(session));
772 		if (err != 0) {
773 			int t = gnutls_dtls_get_timeout(session);
774 			await(sock, t ? t : 100);
775 		}
776 	} while (err != 0);
777 	process_error_or_timeout(err, time(0) - started);
778 
779 	if (debug) {
780 		fprintf(stdout, "%i %s| handshake complete\n", run_id, role_name);
781 	}
782 
783 	if (resume) {
784 		killtimer_set();
785 
786 		do {
787 			await(sock, -1);
788 			len =
789 			    process_error(gnutls_record_recv
790 					  (session, buffer, sizeof(buffer)));
791 		} while (len < 0);
792 
793 		log("received data\n");
794 
795 		die_on_error(gnutls_record_send(session, buffer, len));
796 
797 		log("sent data\n");
798 		exit(0);
799 
800 	} else {
801 		killtimer_set();
802 		die_on_error(gnutls_record_send(session, line, strlen(line)));
803 
804 		log("sent data\n");
805 
806 		do {
807 			await(sock, -1);
808 			len =
809 			    process_error(gnutls_record_recv
810 				  (session, buffer, sizeof(buffer)));
811 		} while (len < 0);
812 
813 		log("received data\n");
814 
815 		if (len > 0 && strncmp(line, buffer, len) == 0) {
816 			exit(0);
817 		} else {
818 			exit(1);
819 		}
820 	}
821 
822 }
823 
824 static gnutls_datum_t saved_data = {NULL, 0};
825 
db_fetch(void * dbf,gnutls_datum_t key)826 static gnutls_datum_t db_fetch(void *dbf, gnutls_datum_t key)
827 {
828 	gnutls_datum_t t = {NULL, 0};
829 	t.data = malloc(saved_data.size);
830 	if (t.data == NULL)
831 		return t;
832 	memcpy(t.data, saved_data.data, saved_data.size);
833 	t.size = saved_data.size;
834 
835 	return t;
836 }
837 
db_delete(void * dbf,gnutls_datum_t key)838 static int db_delete(void *dbf, gnutls_datum_t key)
839 {
840 	return 0;
841 }
842 
db_store(void * dbf,gnutls_datum_t key,gnutls_datum_t data)843 static int db_store(void *dbf, gnutls_datum_t key, gnutls_datum_t data)
844 {
845 	saved_data.data = malloc(data.size);
846 	if (saved_data.data == NULL)
847 		return -1;
848 	memcpy(saved_data.data, data.data, data.size);
849 	saved_data.size = data.size;
850 	return 0;
851 }
852 
server(int sock)853 static void server(int sock)
854 {
855 	int err;
856 	const char *line = "server foobar!";
857 	time_t started = time(0);
858 	char buffer[8192];
859 	int len;
860 
861 	session_init(sock, 1);
862 
863 	await(sock, -1);
864 
865 	killtimer_set();
866 	if (resume) {
867 		gnutls_db_set_retrieve_function(session, db_fetch);
868 		gnutls_db_set_store_function(session, db_store);
869 		gnutls_db_set_remove_function(session, db_delete);
870 		gnutls_db_set_ptr(session, NULL);
871 
872 		do {
873 			err = process_error(gnutls_handshake(session));
874 			if (err != 0) {
875 				int t = gnutls_dtls_get_timeout(session);
876 				await(sock, t ? t : 100);
877 			}
878 		} while (err != 0);
879 		process_error_or_timeout(err, time(0) - started);
880 
881 		gnutls_deinit(session);
882 
883 		session_init(sock, 1);
884 		gnutls_db_set_retrieve_function(session, db_fetch);
885 		gnutls_db_set_store_function(session, db_store);
886 		gnutls_db_set_remove_function(session, db_delete);
887 		gnutls_db_set_ptr(session, NULL);
888 
889 		if (debug) {
890 			fprintf(stdout, "%i %s| initial handshake complete\n", run_id, role_name);
891 		}
892 	}
893 
894 	gnutls_transport_set_push_function(session, writefn);
895 
896 	await(sock, -1);
897 
898 	killtimer_set();
899 	do {
900 		err = process_error(gnutls_handshake(session));
901 		if (err != 0) {
902 			int t = gnutls_dtls_get_timeout(session);
903 			await(sock, t ? t : 100);
904 		}
905 	} while (err != 0);
906 	process_error_or_timeout(err, time(0) - started);
907 
908 	log("handshake complete\n");
909 
910 	if (resume) {
911 		free(saved_data.data);
912 		saved_data.data = NULL;
913 	}
914 
915 	if (resume) {
916 		killtimer_set();
917 		die_on_error(gnutls_record_send(session, line, strlen(line)));
918 
919 		log("sent data\n");
920 
921 		do {
922 			await(sock, -1);
923 			len =
924 			    process_error(gnutls_record_recv
925 				  (session, buffer, sizeof(buffer)));
926 		} while (len < 0);
927 
928 		log("received data\n");
929 
930 		if (len > 0 && strncmp(line, buffer, len) == 0) {
931 			exit(0);
932 		} else {
933 			exit(1);
934 		}
935 	} else {
936 		killtimer_set();
937 
938 		do {
939 			await(sock, -1);
940 			len =
941 			    process_error(gnutls_record_recv
942 					  (session, buffer, sizeof(buffer)));
943 		} while (len < 0);
944 
945 		log("received data\n");
946 
947 		die_on_error(gnutls_record_send(session, buffer, len));
948 
949 		log("sent data\n");
950 	}
951 
952 	exit(0);
953 }
954 
955 // }}}
956 
957 // {{{ test running/handling itself
958 
959 #if 0
960 static void udp_sockpair(int *socks)
961 {
962 	struct sockaddr_in6 sa =
963 	    { AF_INET6, htons(30000), 0, in6addr_loopback, 0 };
964 	struct sockaddr_in6 sb =
965 	    { AF_INET6, htons(20000), 0, in6addr_loopback, 0 };
966 
967 	socks[0] = socket(AF_INET6, SOCK_DGRAM, 0);
968 	socks[1] = socket(AF_INET6, SOCK_DGRAM, 0);
969 
970 	bind(socks[0], (struct sockaddr *)&sa, sizeof(sa));
971 	bind(socks[1], (struct sockaddr *)&sb, sizeof(sb));
972 
973 	connect(socks[1], (struct sockaddr *)&sa, sizeof(sa));
974 	connect(socks[0], (struct sockaddr *)&sb, sizeof(sb));
975 }
976 #endif
977 
run_test(void)978 static int run_test(void)
979 {
980 	int fds[2];
981 	int pid1, pid2;
982 	int status2;
983 
984 	if (socketpair(AF_LOCAL, SOCK_STREAM, 0, fds) < 0) {
985 		rperror("socketpair");
986 		exit(2);
987 	}
988 
989 	if (nonblock) {
990 		fcntl(fds[0], F_SETFL, (long)O_NONBLOCK);
991 		fcntl(fds[1], F_SETFL, (long)O_NONBLOCK);
992 	}
993 
994 	if (!(pid1 = fork())) {
995 		role = SERVER;
996 		server(fds[1]);	// noreturn
997 	} else if (pid1 < 0) {
998 		rperror("fork server");
999 		exit(2);
1000 	}
1001 	if (!(pid2 = fork())) {
1002 		role = CLIENT;
1003 		client(fds[0]);	// noreturn
1004 	} else if (pid2 < 0) {
1005 		rperror("fork client");
1006 		exit(2);
1007 	}
1008 	while (waitpid(pid2, &status2, 0) < 0 && errno == EINTR) ;
1009 	kill(pid1, 15);
1010 	while (waitpid(pid1, 0, 0) < 0 && errno == EINTR) ;
1011 
1012 	close(fds[0]);
1013 	close(fds[1]);
1014 
1015 	if (!WIFSIGNALED(status2) && WEXITSTATUS(status2) != 3) {
1016 		return ! !WEXITSTATUS(status2);
1017 	} else {
1018 		return 3;
1019 	}
1020 }
1021 
1022 static filter_fn filters[]
1023     = { filter_packet_ServerHello,
1024 	filter_packet_ServerKeyExchange,
1025 	filter_packet_ServerHelloDone,
1026 	filter_packet_ClientKeyExchange,
1027 	filter_packet_ClientChangeCipherSpec,
1028 	filter_packet_ClientFinished,
1029 	filter_packet_ServerChangeCipherSpec,
1030 	filter_packet_ServerFinished
1031 };
1032 
1033 static filter_fn filters_resume[]
1034     = { filter_packet_ServerHello,
1035 	filter_packet_ServerChangeCipherSpec,
1036 	filter_packet_ServerFinished,
1037 	filter_packet_ClientChangeCipherSpec,
1038 	filter_packet_ClientFinished
1039 };
1040 
1041 static filter_fn filters_full[]
1042     = { filter_packet_ServerHello,
1043 	filter_packet_ServerCertificate,
1044 	filter_packet_ServerKeyExchange,
1045 	filter_packet_ServerCertificateRequest,
1046 	filter_packet_ServerHelloDone,
1047 	filter_packet_ClientCertificate,
1048 	filter_packet_ClientKeyExchange,
1049 	filter_packet_ClientCertificateVerify,
1050 	filter_packet_ClientChangeCipherSpec,
1051 	filter_packet_ClientFinished,
1052 	filter_packet_ServerChangeCipherSpec,
1053 	filter_packet_ServerFinished
1054 };
1055 
run_one_test(int dropMode,int serverFinishedPermute,int serverHelloPermute,int clientFinishedPermute)1056 static int run_one_test(int dropMode, int serverFinishedPermute,
1057 			int serverHelloPermute, int clientFinishedPermute)
1058 {
1059 	int fnIdx = 0;
1060 	int res, filterIdx;
1061 	filter_fn *local_filters;
1062 	const char **local_filter_names;
1063 	const char **client_finished_permutation_names;
1064 	const char **server_finished_permutation_names;
1065 	const char **server_hello_permutation_names;
1066 	int filter_count;
1067 
1068 	if (full) {
1069 		local_filters = filters_full;
1070 		local_filter_names = filter_names_full;
1071 		filter_count = sizeof(filters_full)/sizeof(filters_full[0]);
1072 		client_finished_permutation_names = permutation_names5;
1073 		server_finished_permutation_names = permutation_names2;
1074 		server_hello_permutation_names = permutation_names5;
1075 	} else if (resume) {
1076 		local_filters = filters_resume;
1077 		local_filter_names = filter_names_resume;
1078 		filter_count = sizeof(filters_resume)/sizeof(filters_resume[0]);
1079 		client_finished_permutation_names = permutation_names2;
1080 		server_finished_permutation_names = permutation_names3;
1081 		server_hello_permutation_names = NULL;
1082 	} else {
1083 		local_filters = filters;
1084 		local_filter_names = filter_names;
1085 		filter_count = sizeof(filters)/sizeof(filters[0]);
1086 		client_finished_permutation_names = permutation_names3;
1087 		server_finished_permutation_names = permutation_names2;
1088 		server_hello_permutation_names = permutation_names3;
1089 	}
1090 
1091 	run_id =
1092 	    ((dropMode * 2 + serverFinishedPermute) * (full ? 120 : 6) +
1093 	     serverHelloPermute) * (full ? 120 : 6) + clientFinishedPermute;
1094 
1095 	filter_clear_state();
1096 
1097 	if (full) {
1098 		filter_chain[fnIdx++] = filter_permute_ServerHelloFull;
1099 		state_permute_ServerHelloFull.order =
1100 		    permutations5[serverHelloPermute];
1101 
1102 		filter_chain[fnIdx++] = filter_permute_ClientFinishedFull;
1103 		state_permute_ClientFinishedFull.order =
1104 		    permutations5[clientFinishedPermute];
1105 
1106 		filter_chain[fnIdx++] = filter_permute_ServerFinished;
1107 		state_permute_ServerFinished.order =
1108 		    permutations2[serverFinishedPermute];
1109 	} else if (resume) {
1110 		filter_chain[fnIdx++] = filter_permute_ServerFinishedResume;
1111 		state_permute_ServerFinishedResume.order =
1112 		    permutations3[serverFinishedPermute];
1113 
1114 		filter_chain[fnIdx++] = filter_permute_ClientFinishedResume;
1115 		state_permute_ClientFinishedResume.order =
1116 		    permutations2[clientFinishedPermute];
1117 	} else {
1118 		filter_chain[fnIdx++] = filter_permute_ServerHello;
1119 		state_permute_ServerHello.order =
1120 		    permutations3[serverHelloPermute];
1121 
1122 		filter_chain[fnIdx++] = filter_permute_ClientFinished;
1123 		state_permute_ClientFinished.order =
1124 		    permutations3[clientFinishedPermute];
1125 
1126 		filter_chain[fnIdx++] = filter_permute_ServerFinished;
1127 		state_permute_ServerFinished.order =
1128 		    permutations2[serverFinishedPermute];
1129 	}
1130 
1131 	if (dropMode) {
1132 		for (filterIdx = 0; filterIdx < filter_count; filterIdx++) {
1133 			if (dropMode & (1 << filterIdx)) {
1134 				filter_chain[fnIdx++] =
1135 				    local_filters[filterIdx];
1136 			}
1137 		}
1138 	}
1139 	filter_chain[fnIdx++] = NULL;
1140 
1141 	res = run_test();
1142 
1143 	switch (res) {
1144 	case 0:
1145 		fprintf(stdout, "%i ++ ", run_id);
1146 		break;
1147 	case 1:
1148 		fprintf(stdout, "%i -- ", run_id);
1149 		break;
1150 	case 2:
1151 		fprintf(stdout, "%i !! ", run_id);
1152 		break;
1153 	case 3:
1154 		fprintf(stdout, "%i TT ", run_id);
1155 		break;
1156 	}
1157 
1158 	if (!resume)
1159 		fprintf(stdout, "SHello(%s), ", server_hello_permutation_names[serverHelloPermute]);
1160 	fprintf(stdout, "SFinished(%s), ",
1161 		server_finished_permutation_names[serverFinishedPermute]);
1162 	fprintf(stdout, "CFinished(%s) :- ",
1163 		client_finished_permutation_names[clientFinishedPermute]);
1164 	if (dropMode) {
1165 		for (filterIdx = 0; filterIdx < filter_count; filterIdx++) {
1166 			if (dropMode & (1 << filterIdx)) {
1167 				if (dropMode & ((1 << filterIdx) - 1)) {
1168 					fprintf(stdout, ", ");
1169 				}
1170 				fprintf(stdout, "%s",
1171 					local_filter_names[filterIdx]);
1172 			}
1173 		}
1174 	}
1175 	fprintf(stdout, "\n");
1176 
1177 	return res;
1178 }
1179 
run_test_by_id(int id)1180 static int run_test_by_id(int id)
1181 {
1182 	int pscale = full ? 120 : 6;
1183 	int dropMode, serverFinishedPermute, serverHelloPermute,
1184 	    clientFinishedPermute;
1185 
1186 	clientFinishedPermute = id % pscale;
1187 	id /= pscale;
1188 
1189 	serverHelloPermute = id % pscale;
1190 	id /= pscale;
1191 
1192 	serverFinishedPermute = id % 2;
1193 	id /= 2;
1194 
1195 	dropMode = id;
1196 
1197 	return run_one_test(dropMode, serverFinishedPermute,
1198 			    serverHelloPermute, clientFinishedPermute);
1199 }
1200 
1201 int *job_pids;
1202 int job_limit;
1203 int children = 0;
1204 
register_child(int pid)1205 static void register_child(int pid)
1206 {
1207 	int idx;
1208 
1209 	children++;
1210 	for (idx = 0; idx < job_limit; idx++) {
1211 		if (job_pids[idx] == 0) {
1212 			job_pids[idx] = pid;
1213 			return;
1214 		}
1215 	}
1216 }
1217 
wait_children(int child_limit)1218 static int wait_children(int child_limit)
1219 {
1220 	int fail = 0;
1221 	int result = 1;
1222 
1223 	while (children > child_limit) {
1224 		int status;
1225 		int idx;
1226 		int pid = waitpid(0, &status, 0);
1227 		if (pid < 0 && errno == ECHILD) {
1228 			break;
1229 		}
1230 		for (idx = 0; idx < job_limit; idx++) {
1231 			if (job_pids[idx] == pid) {
1232 				children--;
1233 				if (WEXITSTATUS(status)) {
1234 					result = 1;
1235 					if (!run_to_end && !fail) {
1236 						fprintf(stderr,
1237 							"One test failed, waiting for remaining tests\n");
1238 						fail = 1;
1239 						child_limit = 0;
1240 					}
1241 				}
1242 				job_pids[idx] = 0;
1243 				break;
1244 			}
1245 		}
1246 	}
1247 
1248 	if (fail) {
1249 		exit(1);
1250 	}
1251 
1252 	return result;
1253 }
1254 
run_tests_from_id_list(int childcount)1255 static int run_tests_from_id_list(int childcount)
1256 {
1257 	int test_id;
1258 	int ret;
1259 	int result = 0;
1260 
1261 	while ((ret = fscanf(stdin, "%i\n", &test_id)) > 0) {
1262 		int pid;
1263 		if (test_id < 0
1264 		    || test_id >
1265 		    2 * (full ? 120 * 120 * (1 << 12) : 6 * 6 * 256)) {
1266 			fprintf(stderr, "Invalid test id %i\n", test_id);
1267 			break;
1268 		}
1269 		if (!(pid = fork())) {
1270 			exit(run_test_by_id(test_id));
1271 		} else if (pid < 0) {
1272 			rperror("fork");
1273 			result = 4;
1274 			break;
1275 		} else {
1276 			register_child(pid);
1277 			result |= wait_children(childcount);
1278 		}
1279 	}
1280 
1281 	if (ret < 0 && ret != EOF) {
1282 		fprintf(stderr, "Error reading test id list\n");
1283 	}
1284 
1285 	result |= wait_children(0);
1286 
1287 	return result;
1288 }
1289 
run_all_tests(int childcount)1290 static int run_all_tests(int childcount)
1291 {
1292 	int dropMode, serverFinishedPermute, serverHelloPermute,
1293 	    clientFinishedPermute;
1294 	int result = 0;
1295 
1296 	for (dropMode = 0; dropMode != 1 << (full ? 12 : 8); dropMode++)
1297 		for (serverFinishedPermute = 0; serverFinishedPermute < 2;
1298 		     serverFinishedPermute++)
1299 			for (serverHelloPermute = 0;
1300 			     serverHelloPermute < (full ? 120 : 6);
1301 			     serverHelloPermute++)
1302 				for (clientFinishedPermute = 0;
1303 				     clientFinishedPermute <
1304 				     (full ? 120 : 6);
1305 				     clientFinishedPermute++) {
1306 					int pid;
1307 					if (!(pid = fork())) {
1308 						exit(run_one_test
1309 						     (dropMode,
1310 						      serverFinishedPermute,
1311 						      serverHelloPermute,
1312 						      clientFinishedPermute));
1313 					} else if (pid < 0) {
1314 						rperror("fork");
1315 						result = 4;
1316 						break;
1317 					} else {
1318 						register_child(pid);
1319 						result |=
1320 						    wait_children(childcount);
1321 					}
1322 				}
1323 
1324 	result |= wait_children(0);
1325 
1326 	return result;
1327 }
1328 
1329 // }}}
1330 
parse_permutation(const char * arg,const char * permutations[],int * val)1331 static int parse_permutation(const char *arg, const char *permutations[],
1332 			     int *val)
1333 {
1334 	*val = 0;
1335 	while (permutations[*val]) {
1336 		if (strcmp(permutations[*val], arg) == 0) {
1337 			return 1;
1338 		} else {
1339 			*val += 1;
1340 		}
1341 	}
1342 	return 0;
1343 }
1344 
main(int argc,const char * argv[])1345 int main(int argc, const char *argv[])
1346 {
1347 	int dropMode = 0;
1348 	int serverFinishedPermute = 0;
1349 	int serverHelloPermute = 0;
1350 	int clientFinishedPermute = 0;
1351 	int batch = 0;
1352 	unsigned single = 0;
1353 	int arg;
1354 
1355 	nonblock = 0;
1356 	replay = 0;
1357 	debug = 0;
1358 	timeout_seconds = 120;
1359 	retransmit_milliseconds = 100;
1360 	full = 0;
1361 	run_to_end = 1;
1362 	job_limit = 1;
1363 
1364 #define NEXT_ARG(name) \
1365 	do { \
1366 		if (++arg >= argc) { \
1367 			fprintf(stderr, "No argument for -" #name "\n"); \
1368 			exit(8); \
1369 		} \
1370 	} while (0);
1371 #define FAIL_ARG(name) \
1372 	do { \
1373 		fprintf(stderr, "Invalid argument for -" #name "\n"); \
1374 		exit(8); \
1375 	} while (0);
1376 
1377 	for (arg = 1; arg < argc; arg++) {
1378 		if (strcmp("-die", argv[arg]) == 0) {
1379 			run_to_end = 0;
1380 		} else if (strcmp("-batch", argv[arg]) == 0) {
1381 			batch = 1;
1382 		} else if (strcmp("-d", argv[arg]) == 0) {
1383 			char *end;
1384 			int level;
1385 
1386 			if (arg+1 < argc) {
1387 				level = strtol(argv[arg + 1], &end, 10);
1388 				if (*end == '\0') {
1389 					debug = level;
1390 					arg++;
1391 				} else
1392 					debug++;
1393 			} else {
1394 				debug++;
1395 			}
1396 		} else if (strcmp("-nb", argv[arg]) == 0) {
1397 			nonblock = 1;
1398 		} else if (strcmp("-r", argv[arg]) == 0) {
1399 			replay = 1;
1400 		} else if (strcmp("-timeout", argv[arg]) == 0) {
1401 			char *end;
1402 			int val;
1403 
1404 			NEXT_ARG(timeout);
1405 			val = strtol(argv[arg], &end, 10);
1406 			if (*end == '\0') {
1407 				timeout_seconds = val;
1408 			} else {
1409 				FAIL_ARG(timeout);
1410 			}
1411 		} else if (strcmp("-retransmit", argv[arg]) == 0) {
1412 			char *end;
1413 			int val;
1414 
1415 			NEXT_ARG(retransmit);
1416 			val = strtol(argv[arg], &end, 10);
1417 			if (*end == '\0') {
1418 				retransmit_milliseconds = val;
1419 			} else {
1420 				FAIL_ARG(retransmit);
1421 			}
1422 		} else if (strcmp("-j", argv[arg]) == 0) {
1423 			char *end;
1424 			int val;
1425 
1426 			NEXT_ARG(timeout);
1427 			val = strtol(argv[arg], &end, 10);
1428 			if (*end == '\0') {
1429 				job_limit = val;
1430 			} else {
1431 				FAIL_ARG(j);
1432 			}
1433 		} else if (strcmp("-full", argv[arg]) == 0) {
1434 			if (resume) {
1435 				fprintf(stderr, "You cannot combine full with resume\n");
1436 				exit(1);
1437 			}
1438 
1439 			full = 1;
1440 		} else if (strcmp("-resume", argv[arg]) == 0) {
1441 			if (full) {
1442 				fprintf(stderr, "You cannot combine full with resume\n");
1443 				exit(1);
1444 			}
1445 
1446 			resume = 1;
1447 		} else if (strcmp("-shello", argv[arg]) == 0) {
1448 			if (resume) {
1449 				fprintf(stderr, "Please use -sfinished instead of -shello\n");
1450 				exit(1);
1451 			}
1452 
1453 			NEXT_ARG(shello);
1454 			if (!parse_permutation
1455 			    (argv[arg],
1456 			     full ? permutation_names5 :
1457 			     permutation_names3, &serverHelloPermute)) {
1458 				FAIL_ARG(shell);
1459 			}
1460 			single++;
1461 		} else if (strcmp("-sfinished", argv[arg]) == 0) {
1462 			const char **pname;
1463 			NEXT_ARG(cfinished);
1464 			if (resume) pname = permutation_names3;
1465 			else pname = permutation_names2;
1466 			if (!parse_permutation
1467 			    (argv[arg], pname,
1468 			     &serverFinishedPermute)) {
1469 				FAIL_ARG(cfinished);
1470 			}
1471 			single++;
1472 		} else if (strcmp("-cfinished", argv[arg]) == 0) {
1473 			const char **pname;
1474 			NEXT_ARG(cfinished);
1475 			if (full) pname = permutation_names5;
1476 			else if (resume) pname = permutation_names2;
1477 			else pname = permutation_names3;
1478 			if (!parse_permutation
1479 			    (argv[arg], pname,
1480 			     &clientFinishedPermute)) {
1481 				FAIL_ARG(cfinished);
1482 			}
1483 			single++;
1484 		} else {
1485 			int drop;
1486 			int filter_count;
1487 			const char **local_filter_names;
1488 
1489 			if (full) {
1490 				local_filter_names = filter_names_full;
1491 				filter_count = sizeof(filters_full)/sizeof(filters_full[0]);
1492 			} else if (resume) {
1493 				local_filter_names = filter_names_resume;
1494 				filter_count = sizeof(filters_resume)/sizeof(filters_resume[0]);
1495 			} else {
1496 				local_filter_names = filter_names;
1497 				filter_count = sizeof(filters)/sizeof(filters[0]);
1498 			}
1499 
1500 			for (drop = 0; drop < filter_count; drop++) {
1501 				if (strcmp
1502 				    (local_filter_names[drop],
1503 				     argv[arg]) == 0) {
1504 					dropMode |= (1 << drop);
1505 					break;
1506 				}
1507 			}
1508 			if (drop == filter_count) {
1509 				fprintf(stderr, "Unknown packet %s\n",
1510 					argv[arg]);
1511 				exit(8);
1512 			}
1513 			single++;
1514 		}
1515 	}
1516 
1517 	setlinebuf(stdout);
1518 	global_init();
1519 	cred_init();
1520 	gnutls_global_set_log_function(logfn);
1521 	gnutls_global_set_audit_log_function(auditfn);
1522 	gnutls_global_set_log_level(debug);
1523 
1524 	if (single) {
1525 		if (debug)
1526 			fprintf(stderr, "single test mode\n");
1527 		return run_one_test(dropMode, serverFinishedPermute,
1528 				    serverHelloPermute, clientFinishedPermute);
1529 	} else {
1530 		if (debug)
1531 			fprintf(stderr, "multi test mode\n");
1532 
1533 		if (resume) {
1534 			fprintf(stderr, "full run not implemented yet for resumed runs\n");
1535 			exit(5);
1536 		}
1537 
1538 		job_pids = calloc(sizeof(int), job_limit);
1539 		if (batch) {
1540 			return run_tests_from_id_list(job_limit);
1541 		} else {
1542 			return run_all_tests(job_limit);
1543 		}
1544 	}
1545 }
1546 
1547 // vim: foldmethod=marker
1548 
1549 #else				/* NO POSIX TIMERS */
1550 
main(int argc,const char * argv[])1551 int main(int argc, const char *argv[])
1552 {
1553 	exit(77);
1554 }
1555 
1556 #endif
1557