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