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