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