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