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