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