1 /* 	$OpenBSD: test_iterate.c,v 1.7 2020/12/21 01:31:06 djm Exp $ */
2 /*
3  * Regress test for hostfile.h hostkeys_foreach()
4  *
5  * Placed in the public domain
6  */
7 
8 #include "includes.h"
9 
10 #include <sys/types.h>
11 #include <sys/param.h>
12 #include <stdio.h>
13 #ifdef HAVE_STDINT_H
14 #include <stdint.h>
15 #endif
16 #include <stdlib.h>
17 #include <string.h>
18 
19 #include "../test_helper/test_helper.h"
20 
21 #include "sshkey.h"
22 #include "authfile.h"
23 #include "hostfile.h"
24 
25 struct expected {
26 	const char *key_file;		/* Path for key, NULL for none */
27 	int no_parse_status;		/* Expected status w/o key parsing */
28 	int no_parse_keytype;		/* Expected keytype w/o key parsing */
29 	int match_host_p;		/* Match 'prometheus.example.com' */
30 	int match_host_s;		/* Match 'sisyphus.example.com' */
31 	int match_ipv4;			/* Match '192.0.2.1' */
32 	int match_ipv6;			/* Match '2001:db8::1' */
33 	int match_flags;		/* Expected flags from match */
34 	struct hostkey_foreach_line l;	/* Expected line contents */
35 };
36 
37 struct cbctx {
38 	const struct expected *expected;
39 	size_t nexpected;
40 	size_t i;
41 	int flags;
42 	int match_host_p;
43 	int match_host_s;
44 	int match_ipv4;
45 	int match_ipv6;
46 };
47 
48 /*
49  * hostkeys_foreach() iterator callback that verifies the line passed
50  * against an array of expected entries.
51  */
52 static int
check(struct hostkey_foreach_line * l,void * _ctx)53 check(struct hostkey_foreach_line *l, void *_ctx)
54 {
55 	struct cbctx *ctx = (struct cbctx *)_ctx;
56 	const struct expected *expected;
57 	int parse_key = (ctx->flags & HKF_WANT_PARSE_KEY) != 0;
58 	const int matching = (ctx->flags & HKF_WANT_MATCH) != 0;
59 	u_int expected_status, expected_match;
60 	int expected_keytype, skip = 0;
61 
62 	test_subtest_info("entry %zu/%zu, file line %ld",
63 	    ctx->i + 1, ctx->nexpected, l->linenum);
64 
65 	for (;;) {
66 		ASSERT_SIZE_T_LT(ctx->i, ctx->nexpected);
67 		expected = ctx->expected + ctx->i++;
68 		/* If we are matching host/IP then skip entries that don't */
69 		if (!matching)
70 			break;
71 		if (ctx->match_host_p && expected->match_host_p)
72 			break;
73 		if (ctx->match_host_s && expected->match_host_s)
74 			break;
75 		if (ctx->match_ipv4 && expected->match_ipv4)
76 			break;
77 		if (ctx->match_ipv6 && expected->match_ipv6)
78 			break;
79 	}
80 	expected_status = (parse_key || expected->no_parse_status < 0) ?
81 	    expected->l.status : (u_int)expected->no_parse_status;
82 	expected_match = expected->l.match;
83 #define UPDATE_MATCH_STATUS(x) do { \
84 		if (ctx->x && expected->x) { \
85 			expected_match |= expected->x; \
86 			if (expected_status == HKF_STATUS_OK) \
87 				expected_status = HKF_STATUS_MATCHED; \
88 		} \
89 	} while (0)
90 	expected_keytype = (parse_key || expected->no_parse_keytype < 0) ?
91 	    expected->l.keytype : expected->no_parse_keytype;
92 
93 #ifndef OPENSSL_HAS_ECC
94 	if (expected->l.keytype == KEY_ECDSA ||
95 	    expected->no_parse_keytype == KEY_ECDSA)
96 		skip = 1;
97 #endif /* OPENSSL_HAS_ECC */
98 #ifndef WITH_OPENSSL
99 	if (expected->l.keytype == KEY_DSA ||
100 	    expected->no_parse_keytype == KEY_DSA ||
101 	    expected->l.keytype == KEY_RSA ||
102 	    expected->no_parse_keytype == KEY_RSA ||
103 	    expected->l.keytype == KEY_ECDSA ||
104 	    expected->no_parse_keytype == KEY_ECDSA)
105 		skip = 1;
106 #endif /* WITH_OPENSSL */
107 	if (skip) {
108 		expected_status = HKF_STATUS_INVALID;
109 		expected_keytype = KEY_UNSPEC;
110 		parse_key = 0;
111 	}
112 	UPDATE_MATCH_STATUS(match_host_p);
113 	UPDATE_MATCH_STATUS(match_host_s);
114 	UPDATE_MATCH_STATUS(match_ipv4);
115 	UPDATE_MATCH_STATUS(match_ipv6);
116 
117 	ASSERT_PTR_NE(l->path, NULL); /* Don't care about path */
118 	ASSERT_LONG_LONG_EQ(l->linenum, expected->l.linenum);
119 	ASSERT_U_INT_EQ(l->status, expected_status);
120 	ASSERT_U_INT_EQ(l->match, expected_match);
121 	/* Not all test entries contain fulltext */
122 	if (expected->l.line != NULL)
123 		ASSERT_STRING_EQ(l->line, expected->l.line);
124 	ASSERT_INT_EQ(l->marker, expected->l.marker);
125 	/* XXX we skip hashed hostnames for now; implement checking */
126 	if (expected->l.hosts != NULL)
127 		ASSERT_STRING_EQ(l->hosts, expected->l.hosts);
128 	/* Not all test entries contain raw keys */
129 	if (expected->l.rawkey != NULL)
130 		ASSERT_STRING_EQ(l->rawkey, expected->l.rawkey);
131 	/* XXX synthesise raw key for cases lacking and compare */
132 	ASSERT_INT_EQ(l->keytype, expected_keytype);
133 	if (parse_key) {
134 		if (expected->l.key == NULL)
135 			ASSERT_PTR_EQ(l->key, NULL);
136 		if (expected->l.key != NULL) {
137 			ASSERT_PTR_NE(l->key, NULL);
138 			ASSERT_INT_EQ(sshkey_equal(l->key, expected->l.key), 1);
139 		}
140 	}
141 	if (parse_key && !(l->comment == NULL && expected->l.comment == NULL))
142 		ASSERT_STRING_EQ(l->comment, expected->l.comment);
143 	return 0;
144 }
145 
146 /* Loads public keys for a set of expected results */
147 static void
prepare_expected(struct expected * expected,size_t n)148 prepare_expected(struct expected *expected, size_t n)
149 {
150 	size_t i;
151 
152 	for (i = 0; i < n; i++) {
153 		if (expected[i].key_file == NULL)
154 			continue;
155 #ifndef OPENSSL_HAS_ECC
156 		if (expected[i].l.keytype == KEY_ECDSA)
157 			continue;
158 #endif /* OPENSSL_HAS_ECC */
159 #ifndef WITH_OPENSSL
160 		switch (expected[i].l.keytype) {
161 		case KEY_RSA:
162 		case KEY_DSA:
163 		case KEY_ECDSA:
164 			continue;
165 		}
166 #endif /* WITH_OPENSSL */
167 		ASSERT_INT_EQ(sshkey_load_public(
168 		    test_data_file(expected[i].key_file), &expected[i].l.key,
169 		    NULL), 0);
170 	}
171 }
172 
173 static void
cleanup_expected(struct expected * expected,size_t n)174 cleanup_expected(struct expected *expected, size_t n)
175 {
176 	size_t i;
177 
178 	for (i = 0; i < n; i++) {
179 		sshkey_free(expected[i].l.key);
180 		expected[i].l.key = NULL;
181 	}
182 }
183 
184 struct expected expected_full[] = {
185 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
186 		NULL,				/* path, don't care */
187 		1,				/* line number */
188 		HKF_STATUS_COMMENT,		/* status */
189 		0,				/* match flags */
190 		"# Plain host keys, plain host names", /* full line, optional */
191 		MRK_NONE,			/* marker (CA / revoked) */
192 		NULL,				/* hosts text */
193 		NULL,				/* raw key, optional */
194 		KEY_UNSPEC,			/* key type */
195 		NULL,				/* deserialised key */
196 		NULL,				/* comment */
197 		0,				/* note */
198 	} },
199 	{ "dsa_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
200 		NULL,
201 		2,
202 		HKF_STATUS_OK,
203 		0,
204 		NULL,
205 		MRK_NONE,
206 		"sisyphus.example.com",
207 		NULL,
208 		KEY_DSA,
209 		NULL,	/* filled at runtime */
210 		"DSA #1",
211 		0,
212 	} },
213 	{ "ecdsa_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
214 		NULL,
215 		3,
216 		HKF_STATUS_OK,
217 		0,
218 		NULL,
219 		MRK_NONE,
220 		"sisyphus.example.com",
221 		NULL,
222 		KEY_ECDSA,
223 		NULL,	/* filled at runtime */
224 		"ECDSA #1",
225 		0,
226 	} },
227 	{ "ed25519_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
228 		NULL,
229 		4,
230 		HKF_STATUS_OK,
231 		0,
232 		NULL,
233 		MRK_NONE,
234 		"sisyphus.example.com",
235 		NULL,
236 		KEY_ED25519,
237 		NULL,	/* filled at runtime */
238 		"ED25519 #1",
239 		0,
240 	} },
241 	{ "rsa_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
242 		NULL,
243 		5,
244 		HKF_STATUS_OK,
245 		0,
246 		NULL,
247 		MRK_NONE,
248 		"sisyphus.example.com",
249 		NULL,
250 		KEY_RSA,
251 		NULL,	/* filled at runtime */
252 		"RSA #1",
253 		0,
254 	} },
255 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
256 		NULL,
257 		6,
258 		HKF_STATUS_COMMENT,
259 		0,
260 		"",
261 		MRK_NONE,
262 		NULL,
263 		NULL,
264 		KEY_UNSPEC,
265 		NULL,
266 		NULL,
267 		0,
268 	} },
269 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
270 		NULL,
271 		7,
272 		HKF_STATUS_COMMENT,
273 		0,
274 		"# Plain host keys, hostnames + addresses",
275 		MRK_NONE,
276 		NULL,
277 		NULL,
278 		KEY_UNSPEC,
279 		NULL,
280 		NULL,
281 		0,
282 	} },
283 	{ "dsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
284 		NULL,
285 		8,
286 		HKF_STATUS_OK,
287 		0,
288 		NULL,
289 		MRK_NONE,
290 		"prometheus.example.com,192.0.2.1,2001:db8::1",
291 		NULL,
292 		KEY_DSA,
293 		NULL,	/* filled at runtime */
294 		"DSA #2",
295 		0,
296 	} },
297 	{ "ecdsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
298 		NULL,
299 		9,
300 		HKF_STATUS_OK,
301 		0,
302 		NULL,
303 		MRK_NONE,
304 		"prometheus.example.com,192.0.2.1,2001:db8::1",
305 		NULL,
306 		KEY_ECDSA,
307 		NULL,	/* filled at runtime */
308 		"ECDSA #2",
309 		0,
310 	} },
311 	{ "ed25519_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
312 		NULL,
313 		10,
314 		HKF_STATUS_OK,
315 		0,
316 		NULL,
317 		MRK_NONE,
318 		"prometheus.example.com,192.0.2.1,2001:db8::1",
319 		NULL,
320 		KEY_ED25519,
321 		NULL,	/* filled at runtime */
322 		"ED25519 #2",
323 		0,
324 	} },
325 	{ "rsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
326 		NULL,
327 		11,
328 		HKF_STATUS_OK,
329 		0,
330 		NULL,
331 		MRK_NONE,
332 		"prometheus.example.com,192.0.2.1,2001:db8::1",
333 		NULL,
334 		KEY_RSA,
335 		NULL,	/* filled at runtime */
336 		"RSA #2",
337 		0,
338 	} },
339 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
340 		NULL,
341 		12,
342 		HKF_STATUS_COMMENT,
343 		0,
344 		"",
345 		MRK_NONE,
346 		NULL,
347 		NULL,
348 		KEY_UNSPEC,
349 		NULL,
350 		NULL,
351 		0,
352 	} },
353 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
354 		NULL,
355 		13,
356 		HKF_STATUS_COMMENT,
357 		0,
358 		"# Some hosts with wildcard names / IPs",
359 		MRK_NONE,
360 		NULL,
361 		NULL,
362 		KEY_UNSPEC,
363 		NULL,
364 		NULL,
365 		0,
366 	} },
367 	{ "dsa_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
368 		NULL,
369 		14,
370 		HKF_STATUS_OK,
371 		0,
372 		NULL,
373 		MRK_NONE,
374 		"*.example.com,192.0.2.*,2001:*",
375 		NULL,
376 		KEY_DSA,
377 		NULL,	/* filled at runtime */
378 		"DSA #3",
379 		0,
380 	} },
381 	{ "ecdsa_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
382 		NULL,
383 		15,
384 		HKF_STATUS_OK,
385 		0,
386 		NULL,
387 		MRK_NONE,
388 		"*.example.com,192.0.2.*,2001:*",
389 		NULL,
390 		KEY_ECDSA,
391 		NULL,	/* filled at runtime */
392 		"ECDSA #3",
393 		0,
394 	} },
395 	{ "ed25519_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
396 		NULL,
397 		16,
398 		HKF_STATUS_OK,
399 		0,
400 		NULL,
401 		MRK_NONE,
402 		"*.example.com,192.0.2.*,2001:*",
403 		NULL,
404 		KEY_ED25519,
405 		NULL,	/* filled at runtime */
406 		"ED25519 #3",
407 		0,
408 	} },
409 	{ "rsa_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
410 		NULL,
411 		17,
412 		HKF_STATUS_OK,
413 		0,
414 		NULL,
415 		MRK_NONE,
416 		"*.example.com,192.0.2.*,2001:*",
417 		NULL,
418 		KEY_RSA,
419 		NULL,	/* filled at runtime */
420 		"RSA #3",
421 		0,
422 	} },
423 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
424 		NULL,
425 		18,
426 		HKF_STATUS_COMMENT,
427 		0,
428 		"",
429 		MRK_NONE,
430 		NULL,
431 		NULL,
432 		KEY_UNSPEC,
433 		NULL,
434 		NULL,
435 		0,
436 	} },
437 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
438 		NULL,
439 		19,
440 		HKF_STATUS_COMMENT,
441 		0,
442 		"# Hashed hostname and address entries",
443 		MRK_NONE,
444 		NULL,
445 		NULL,
446 		KEY_UNSPEC,
447 		NULL,
448 		NULL,
449 		0,
450 	} },
451 	{ "dsa_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, {
452 		NULL,
453 		20,
454 		HKF_STATUS_OK,
455 		0,
456 		NULL,
457 		MRK_NONE,
458 		NULL,
459 		NULL,
460 		KEY_DSA,
461 		NULL,	/* filled at runtime */
462 		"DSA #5",
463 		0,
464 	} },
465 	{ "ecdsa_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, {
466 		NULL,
467 		21,
468 		HKF_STATUS_OK,
469 		0,
470 		NULL,
471 		MRK_NONE,
472 		NULL,
473 		NULL,
474 		KEY_ECDSA,
475 		NULL,	/* filled at runtime */
476 		"ECDSA #5",
477 		0,
478 	} },
479 	{ "ed25519_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, {
480 		NULL,
481 		22,
482 		HKF_STATUS_OK,
483 		0,
484 		NULL,
485 		MRK_NONE,
486 		NULL,
487 		NULL,
488 		KEY_ED25519,
489 		NULL,	/* filled at runtime */
490 		"ED25519 #5",
491 		0,
492 	} },
493 	{ "rsa_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, {
494 		NULL,
495 		23,
496 		HKF_STATUS_OK,
497 		0,
498 		NULL,
499 		MRK_NONE,
500 		NULL,
501 		NULL,
502 		KEY_RSA,
503 		NULL,	/* filled at runtime */
504 		"RSA #5",
505 		0,
506 	} },
507 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
508 		NULL,
509 		24,
510 		HKF_STATUS_COMMENT,
511 		0,
512 		"",
513 		MRK_NONE,
514 		NULL,
515 		NULL,
516 		KEY_UNSPEC,
517 		NULL,
518 		NULL,
519 		0,
520 	} },
521 	/*
522 	 * The next series have each key listed multiple times, as the
523 	 * hostname and addresses in the pre-hashed known_hosts are split
524 	 * to separate lines.
525 	 */
526 	{ "dsa_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, {
527 		NULL,
528 		25,
529 		HKF_STATUS_OK,
530 		0,
531 		NULL,
532 		MRK_NONE,
533 		NULL,
534 		NULL,
535 		KEY_DSA,
536 		NULL,	/* filled at runtime */
537 		"DSA #6",
538 		0,
539 	} },
540 	{ "dsa_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, {
541 		NULL,
542 		26,
543 		HKF_STATUS_OK,
544 		0,
545 		NULL,
546 		MRK_NONE,
547 		NULL,
548 		NULL,
549 		KEY_DSA,
550 		NULL,	/* filled at runtime */
551 		"DSA #6",
552 		0,
553 	} },
554 	{ "dsa_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, {
555 		NULL,
556 		27,
557 		HKF_STATUS_OK,
558 		0,
559 		NULL,
560 		MRK_NONE,
561 		NULL,
562 		NULL,
563 		KEY_DSA,
564 		NULL,	/* filled at runtime */
565 		"DSA #6",
566 		0,
567 	} },
568 	{ "ecdsa_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, {
569 		NULL,
570 		28,
571 		HKF_STATUS_OK,
572 		0,
573 		NULL,
574 		MRK_NONE,
575 		NULL,
576 		NULL,
577 		KEY_ECDSA,
578 		NULL,	/* filled at runtime */
579 		"ECDSA #6",
580 		0,
581 	} },
582 	{ "ecdsa_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, {
583 		NULL,
584 		29,
585 		HKF_STATUS_OK,
586 		0,
587 		NULL,
588 		MRK_NONE,
589 		NULL,
590 		NULL,
591 		KEY_ECDSA,
592 		NULL,	/* filled at runtime */
593 		"ECDSA #6",
594 		0,
595 	} },
596 	{ "ecdsa_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, {
597 		NULL,
598 		30,
599 		HKF_STATUS_OK,
600 		0,
601 		NULL,
602 		MRK_NONE,
603 		NULL,
604 		NULL,
605 		KEY_ECDSA,
606 		NULL,	/* filled at runtime */
607 		"ECDSA #6",
608 		0,
609 	} },
610 	{ "ed25519_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, {
611 		NULL,
612 		31,
613 		HKF_STATUS_OK,
614 		0,
615 		NULL,
616 		MRK_NONE,
617 		NULL,
618 		NULL,
619 		KEY_ED25519,
620 		NULL,	/* filled at runtime */
621 		"ED25519 #6",
622 		0,
623 	} },
624 	{ "ed25519_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, {
625 		NULL,
626 		32,
627 		HKF_STATUS_OK,
628 		0,
629 		NULL,
630 		MRK_NONE,
631 		NULL,
632 		NULL,
633 		KEY_ED25519,
634 		NULL,	/* filled at runtime */
635 		"ED25519 #6",
636 		0,
637 	} },
638 	{ "ed25519_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, {
639 		NULL,
640 		33,
641 		HKF_STATUS_OK,
642 		0,
643 		NULL,
644 		MRK_NONE,
645 		NULL,
646 		NULL,
647 		KEY_ED25519,
648 		NULL,	/* filled at runtime */
649 		"ED25519 #6",
650 		0,
651 	} },
652 	{ "rsa_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, {
653 		NULL,
654 		34,
655 		HKF_STATUS_OK,
656 		0,
657 		NULL,
658 		MRK_NONE,
659 		NULL,
660 		NULL,
661 		KEY_RSA,
662 		NULL,	/* filled at runtime */
663 		"RSA #6",
664 		0,
665 	} },
666 	{ "rsa_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, {
667 		NULL,
668 		35,
669 		HKF_STATUS_OK,
670 		0,
671 		NULL,
672 		MRK_NONE,
673 		NULL,
674 		NULL,
675 		KEY_RSA,
676 		NULL,	/* filled at runtime */
677 		"RSA #6",
678 		0,
679 	} },
680 	{ "rsa_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, {
681 		NULL,
682 		36,
683 		HKF_STATUS_OK,
684 		0,
685 		NULL,
686 		MRK_NONE,
687 		NULL,
688 		NULL,
689 		KEY_RSA,
690 		NULL,	/* filled at runtime */
691 		"RSA #6",
692 		0,
693 	} },
694 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
695 		NULL,
696 		37,
697 		HKF_STATUS_COMMENT,
698 		0,
699 		"",
700 		MRK_NONE,
701 		NULL,
702 		NULL,
703 		KEY_UNSPEC,
704 		NULL,
705 		NULL,
706 		0,
707 	} },
708 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
709 		NULL,
710 		38,
711 		HKF_STATUS_COMMENT,
712 		0,
713 		"",
714 		MRK_NONE,
715 		NULL,
716 		NULL,
717 		KEY_UNSPEC,
718 		NULL,
719 		NULL,
720 		0,
721 	} },
722 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
723 		NULL,
724 		39,
725 		HKF_STATUS_COMMENT,
726 		0,
727 		"# Revoked and CA keys",
728 		MRK_NONE,
729 		NULL,
730 		NULL,
731 		KEY_UNSPEC,
732 		NULL,
733 		NULL,
734 		0,
735 	} },
736 	{ "ed25519_4.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
737 		NULL,
738 		40,
739 		HKF_STATUS_OK,
740 		0,
741 		NULL,
742 		MRK_REVOKE,
743 		"sisyphus.example.com",
744 		NULL,
745 		KEY_ED25519,
746 		NULL,	/* filled at runtime */
747 		"ED25519 #4",
748 		0,
749 	} },
750 	{ "ecdsa_4.pub" , -1, -1, HKF_MATCH_HOST, 0, 0, 0, -1, {
751 		NULL,
752 		41,
753 		HKF_STATUS_OK,
754 		0,
755 		NULL,
756 		MRK_CA,
757 		"prometheus.example.com",
758 		NULL,
759 		KEY_ECDSA,
760 		NULL,	/* filled at runtime */
761 		"ECDSA #4",
762 		0,
763 	} },
764 	{ "dsa_4.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, 0, 0, -1, {
765 		NULL,
766 		42,
767 		HKF_STATUS_OK,
768 		0,
769 		NULL,
770 		MRK_CA,
771 		"*.example.com",
772 		NULL,
773 		KEY_DSA,
774 		NULL,	/* filled at runtime */
775 		"DSA #4",
776 		0,
777 	} },
778 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
779 		NULL,
780 		43,
781 		HKF_STATUS_COMMENT,
782 		0,
783 		"",
784 		MRK_NONE,
785 		NULL,
786 		NULL,
787 		KEY_UNSPEC,
788 		NULL,
789 		NULL,
790 		0,
791 	} },
792 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
793 		NULL,
794 		44,
795 		HKF_STATUS_COMMENT,
796 		0,
797 		"# Some invalid lines",
798 		MRK_NONE,
799 		NULL,
800 		NULL,
801 		KEY_UNSPEC,
802 		NULL,
803 		NULL,
804 		0,
805 	} },
806 	{ NULL, -1, -1, 0, 0, 0, 0, -1, {
807 		NULL,
808 		45,
809 		HKF_STATUS_INVALID,
810 		0,
811 		NULL,
812 		MRK_ERROR,
813 		NULL,
814 		NULL,
815 		KEY_UNSPEC,
816 		NULL,
817 		NULL,
818 		0,
819 	} },
820 	{ NULL, -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
821 		NULL,
822 		46,
823 		HKF_STATUS_INVALID,
824 		0,
825 		NULL,
826 		MRK_NONE,
827 		"sisyphus.example.com",
828 		NULL,
829 		KEY_UNSPEC,
830 		NULL,
831 		NULL,
832 		0,
833 	} },
834 	{ NULL, -1, -1, HKF_MATCH_HOST, 0, 0, 0, -1, {
835 		NULL,
836 		47,
837 		HKF_STATUS_INVALID,
838 		0,
839 		NULL,
840 		MRK_NONE,
841 		"prometheus.example.com",
842 		NULL,
843 		KEY_UNSPEC,
844 		NULL,
845 		NULL,
846 		0,
847 	} },
848 	{ NULL, -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
849 		NULL,
850 		48,
851 		HKF_STATUS_INVALID,	/* Would be ok if key not parsed */
852 		0,
853 		NULL,
854 		MRK_NONE,
855 		"sisyphus.example.com",
856 		NULL,
857 		KEY_UNSPEC,
858 		NULL,
859 		NULL,
860 		0,
861 	} },
862 	{ NULL, -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
863 		NULL,
864 		49,
865 		HKF_STATUS_INVALID,
866 		0,
867 		NULL,
868 		MRK_NONE,
869 		"sisyphus.example.com",
870 		NULL,
871 		KEY_UNSPEC,
872 		NULL,	/* filled at runtime */
873 		NULL,
874 		0,
875 	} },
876 	{ NULL, HKF_STATUS_OK, KEY_RSA, HKF_MATCH_HOST, 0, 0, 0, -1, {
877 		NULL,
878 		50,
879 		HKF_STATUS_INVALID,	/* Would be ok if key not parsed */
880 		0,
881 		NULL,
882 		MRK_NONE,
883 		"prometheus.example.com",
884 		NULL,
885 		KEY_UNSPEC,
886 		NULL,	/* filled at runtime */
887 		NULL,
888 		0,
889 	} },
890 };
891 
892 void test_iterate(void);
893 
894 void
test_iterate(void)895 test_iterate(void)
896 {
897 	struct cbctx ctx;
898 
899 	TEST_START("hostkeys_iterate all with key parse");
900 	memset(&ctx, 0, sizeof(ctx));
901 	ctx.expected = expected_full;
902 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
903 	ctx.flags = HKF_WANT_PARSE_KEY;
904 	prepare_expected(expected_full, ctx.nexpected);
905 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
906 	    check, &ctx, NULL, NULL, ctx.flags, 0), 0);
907 	cleanup_expected(expected_full, ctx.nexpected);
908 	TEST_DONE();
909 
910 	TEST_START("hostkeys_iterate all without key parse");
911 	memset(&ctx, 0, sizeof(ctx));
912 	ctx.expected = expected_full;
913 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
914 	ctx.flags = 0;
915 	prepare_expected(expected_full, ctx.nexpected);
916 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
917 	    check, &ctx, NULL, NULL, ctx.flags, 0), 0);
918 	cleanup_expected(expected_full, ctx.nexpected);
919 	TEST_DONE();
920 
921 	TEST_START("hostkeys_iterate specify host 1");
922 	memset(&ctx, 0, sizeof(ctx));
923 	ctx.expected = expected_full;
924 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
925 	ctx.flags = 0;
926 	ctx.match_host_p = 1;
927 	prepare_expected(expected_full, ctx.nexpected);
928 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
929 	    check, &ctx, "prometheus.example.com", NULL, ctx.flags, 0), 0);
930 	cleanup_expected(expected_full, ctx.nexpected);
931 	TEST_DONE();
932 
933 	TEST_START("hostkeys_iterate specify host 2");
934 	memset(&ctx, 0, sizeof(ctx));
935 	ctx.expected = expected_full;
936 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
937 	ctx.flags = 0;
938 	ctx.match_host_s = 1;
939 	prepare_expected(expected_full, ctx.nexpected);
940 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
941 	    check, &ctx, "sisyphus.example.com", NULL, ctx.flags, 0), 0);
942 	cleanup_expected(expected_full, ctx.nexpected);
943 	TEST_DONE();
944 
945 	TEST_START("hostkeys_iterate match host 1");
946 	memset(&ctx, 0, sizeof(ctx));
947 	ctx.expected = expected_full;
948 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
949 	ctx.flags = HKF_WANT_MATCH;
950 	ctx.match_host_p = 1;
951 	prepare_expected(expected_full, ctx.nexpected);
952 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
953 	    check, &ctx, "prometheus.example.com", NULL, ctx.flags, 0), 0);
954 	cleanup_expected(expected_full, ctx.nexpected);
955 	TEST_DONE();
956 
957 	TEST_START("hostkeys_iterate match host 2");
958 	memset(&ctx, 0, sizeof(ctx));
959 	ctx.expected = expected_full;
960 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
961 	ctx.flags = HKF_WANT_MATCH;
962 	ctx.match_host_s = 1;
963 	prepare_expected(expected_full, ctx.nexpected);
964 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
965 	    check, &ctx, "sisyphus.example.com", NULL, ctx.flags, 0), 0);
966 	cleanup_expected(expected_full, ctx.nexpected);
967 	TEST_DONE();
968 
969 	TEST_START("hostkeys_iterate specify host missing");
970 	memset(&ctx, 0, sizeof(ctx));
971 	ctx.expected = expected_full;
972 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
973 	ctx.flags = 0;
974 	prepare_expected(expected_full, ctx.nexpected);
975 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
976 	    check, &ctx, "actaeon.example.org", NULL, ctx.flags, 0), 0);
977 	cleanup_expected(expected_full, ctx.nexpected);
978 	TEST_DONE();
979 
980 	TEST_START("hostkeys_iterate match host missing");
981 	memset(&ctx, 0, sizeof(ctx));
982 	ctx.expected = expected_full;
983 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
984 	ctx.flags = HKF_WANT_MATCH;
985 	prepare_expected(expected_full, ctx.nexpected);
986 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
987 	    check, &ctx, "actaeon.example.org", NULL, ctx.flags, 0), 0);
988 	cleanup_expected(expected_full, ctx.nexpected);
989 	TEST_DONE();
990 
991 	TEST_START("hostkeys_iterate specify IPv4");
992 	memset(&ctx, 0, sizeof(ctx));
993 	ctx.expected = expected_full;
994 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
995 	ctx.flags = 0;
996 	ctx.match_ipv4 = 1;
997 	prepare_expected(expected_full, ctx.nexpected);
998 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
999 	    check, &ctx, "tiresias.example.org", "192.0.2.1", ctx.flags, 0), 0);
1000 	cleanup_expected(expected_full, ctx.nexpected);
1001 	TEST_DONE();
1002 
1003 	TEST_START("hostkeys_iterate specify IPv6");
1004 	memset(&ctx, 0, sizeof(ctx));
1005 	ctx.expected = expected_full;
1006 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
1007 	ctx.flags = 0;
1008 	ctx.match_ipv6 = 1;
1009 	prepare_expected(expected_full, ctx.nexpected);
1010 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
1011 	    check, &ctx, "tiresias.example.org", "2001:db8::1",
1012 	    ctx.flags, 0), 0);
1013 	cleanup_expected(expected_full, ctx.nexpected);
1014 	TEST_DONE();
1015 
1016 	TEST_START("hostkeys_iterate match IPv4");
1017 	memset(&ctx, 0, sizeof(ctx));
1018 	ctx.expected = expected_full;
1019 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
1020 	ctx.flags = HKF_WANT_MATCH;
1021 	ctx.match_ipv4 = 1;
1022 	prepare_expected(expected_full, ctx.nexpected);
1023 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
1024 	    check, &ctx, "tiresias.example.org", "192.0.2.1", ctx.flags, 0), 0);
1025 	cleanup_expected(expected_full, ctx.nexpected);
1026 	TEST_DONE();
1027 
1028 	TEST_START("hostkeys_iterate match IPv6");
1029 	memset(&ctx, 0, sizeof(ctx));
1030 	ctx.expected = expected_full;
1031 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
1032 	ctx.flags = HKF_WANT_MATCH;
1033 	ctx.match_ipv6 = 1;
1034 	prepare_expected(expected_full, ctx.nexpected);
1035 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
1036 	    check, &ctx, "tiresias.example.org", "2001:db8::1",
1037 	    ctx.flags, 0), 0);
1038 	cleanup_expected(expected_full, ctx.nexpected);
1039 	TEST_DONE();
1040 
1041 	TEST_START("hostkeys_iterate specify addr missing");
1042 	memset(&ctx, 0, sizeof(ctx));
1043 	ctx.expected = expected_full;
1044 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
1045 	ctx.flags = 0;
1046 	prepare_expected(expected_full, ctx.nexpected);
1047 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
1048 	    check, &ctx, "tiresias.example.org", "192.168.0.1",
1049 	    ctx.flags, 0), 0);
1050 	cleanup_expected(expected_full, ctx.nexpected);
1051 	TEST_DONE();
1052 
1053 	TEST_START("hostkeys_iterate match addr missing");
1054 	memset(&ctx, 0, sizeof(ctx));
1055 	ctx.expected = expected_full;
1056 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
1057 	ctx.flags = HKF_WANT_MATCH;
1058 	prepare_expected(expected_full, ctx.nexpected);
1059 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
1060 	    check, &ctx, "tiresias.example.org", "::1", ctx.flags, 0), 0);
1061 	cleanup_expected(expected_full, ctx.nexpected);
1062 	TEST_DONE();
1063 
1064 	TEST_START("hostkeys_iterate specify host 2 and IPv4");
1065 	memset(&ctx, 0, sizeof(ctx));
1066 	ctx.expected = expected_full;
1067 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
1068 	ctx.flags = 0;
1069 	ctx.match_host_s = 1;
1070 	ctx.match_ipv4 = 1;
1071 	prepare_expected(expected_full, ctx.nexpected);
1072 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
1073 	    check, &ctx, "sisyphus.example.com", "192.0.2.1", ctx.flags, 0), 0);
1074 	cleanup_expected(expected_full, ctx.nexpected);
1075 	TEST_DONE();
1076 
1077 	TEST_START("hostkeys_iterate match host 1 and IPv6");
1078 	memset(&ctx, 0, sizeof(ctx));
1079 	ctx.expected = expected_full;
1080 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
1081 	ctx.flags = HKF_WANT_MATCH;
1082 	ctx.match_host_p = 1;
1083 	ctx.match_ipv6 = 1;
1084 	prepare_expected(expected_full, ctx.nexpected);
1085 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
1086 	    check, &ctx, "prometheus.example.com",
1087 	    "2001:db8::1", ctx.flags, 0), 0);
1088 	cleanup_expected(expected_full, ctx.nexpected);
1089 	TEST_DONE();
1090 
1091 	TEST_START("hostkeys_iterate specify host 2 and IPv4 w/ key parse");
1092 	memset(&ctx, 0, sizeof(ctx));
1093 	ctx.expected = expected_full;
1094 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
1095 	ctx.flags = HKF_WANT_PARSE_KEY;
1096 	ctx.match_host_s = 1;
1097 	ctx.match_ipv4 = 1;
1098 	prepare_expected(expected_full, ctx.nexpected);
1099 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
1100 	    check, &ctx, "sisyphus.example.com", "192.0.2.1", ctx.flags, 0), 0);
1101 	cleanup_expected(expected_full, ctx.nexpected);
1102 	TEST_DONE();
1103 
1104 	TEST_START("hostkeys_iterate match host 1 and IPv6 w/ key parse");
1105 	memset(&ctx, 0, sizeof(ctx));
1106 	ctx.expected = expected_full;
1107 	ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
1108 	ctx.flags = HKF_WANT_MATCH|HKF_WANT_PARSE_KEY;
1109 	ctx.match_host_p = 1;
1110 	ctx.match_ipv6 = 1;
1111 	prepare_expected(expected_full, ctx.nexpected);
1112 	ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
1113 	    check, &ctx, "prometheus.example.com",
1114 	    "2001:db8::1", ctx.flags, 0), 0);
1115 	cleanup_expected(expected_full, ctx.nexpected);
1116 	TEST_DONE();
1117 }
1118 
1119