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