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