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