1 /* $OpenBSD: test_iterate.c,v 1.5 2017/04/30 23:33:48 djm Exp $ */
3 * Regress test for hostfile.h hostkeys_foreach()
5 * Placed in the public domain
10 #include <sys/types.h>
11 #include <sys/param.h>
19 #include "../test_helper/test_helper.h"
26 const char *key_file; /* Path for key, NULL for none */
27 int no_parse_status; /* Expected status w/o key parsing */
28 int no_parse_keytype; /* Expected keytype w/o key parsing */
29 int match_host_p; /* Match 'prometheus.example.com' */
30 int match_host_s; /* Match 'sisyphus.example.com' */
31 int match_ipv4; /* Match '192.0.2.1' */
32 int match_ipv6; /* Match '2001:db8::1' */
33 int match_flags; /* Expected flags from match */
34 struct hostkey_foreach_line l; /* Expected line contents */
38 const struct expected *expected;
49 * hostkeys_foreach() iterator callback that verifies the line passed
50 * against an array of expected entries.
53 check(struct hostkey_foreach_line *l, void *_ctx)
55 struct cbctx *ctx = (struct cbctx *)_ctx;
56 const struct expected *expected;
57 int parse_key = (ctx->flags & HKF_WANT_PARSE_KEY) != 0;
58 const int matching = (ctx->flags & HKF_WANT_MATCH) != 0;
59 u_int expected_status, expected_match;
62 test_subtest_info("entry %zu/%zu, file line %ld",
63 ctx->i + 1, ctx->nexpected, l->linenum);
66 ASSERT_SIZE_T_LT(ctx->i, ctx->nexpected);
67 expected = ctx->expected + ctx->i++;
68 /* If we are matching host/IP then skip entries that don't */
71 if (ctx->match_host_p && expected->match_host_p)
73 if (ctx->match_host_s && expected->match_host_s)
75 if (ctx->match_ipv4 && expected->match_ipv4)
77 if (ctx->match_ipv6 && expected->match_ipv6)
80 expected_status = (parse_key || expected->no_parse_status < 0) ?
81 expected->l.status : (u_int)expected->no_parse_status;
82 expected_match = expected->l.match;
83 #define UPDATE_MATCH_STATUS(x) do { \
84 if (ctx->x && expected->x) { \
85 expected_match |= expected->x; \
86 if (expected_status == HKF_STATUS_OK) \
87 expected_status = HKF_STATUS_MATCHED; \
90 expected_keytype = (parse_key || expected->no_parse_keytype < 0) ?
91 expected->l.keytype : expected->no_parse_keytype;
93 #ifndef OPENSSL_HAS_ECC
94 if (expected->l.keytype == KEY_ECDSA ||
95 expected->no_parse_keytype == KEY_ECDSA) {
96 expected_status = HKF_STATUS_INVALID;
97 expected_keytype = KEY_UNSPEC;
102 UPDATE_MATCH_STATUS(match_host_p);
103 UPDATE_MATCH_STATUS(match_host_s);
104 UPDATE_MATCH_STATUS(match_ipv4);
105 UPDATE_MATCH_STATUS(match_ipv6);
107 ASSERT_PTR_NE(l->path, NULL); /* Don't care about path */
108 ASSERT_LONG_LONG_EQ(l->linenum, expected->l.linenum);
109 ASSERT_U_INT_EQ(l->status, expected_status);
110 ASSERT_U_INT_EQ(l->match, expected_match);
111 /* Not all test entries contain fulltext */
112 if (expected->l.line != NULL)
113 ASSERT_STRING_EQ(l->line, expected->l.line);
114 ASSERT_INT_EQ(l->marker, expected->l.marker);
115 /* XXX we skip hashed hostnames for now; implement checking */
116 if (expected->l.hosts != NULL)
117 ASSERT_STRING_EQ(l->hosts, expected->l.hosts);
118 /* Not all test entries contain raw keys */
119 if (expected->l.rawkey != NULL)
120 ASSERT_STRING_EQ(l->rawkey, expected->l.rawkey);
121 /* XXX synthesise raw key for cases lacking and compare */
122 ASSERT_INT_EQ(l->keytype, expected_keytype);
124 if (expected->l.key == NULL)
125 ASSERT_PTR_EQ(l->key, NULL);
126 if (expected->l.key != NULL) {
127 ASSERT_PTR_NE(l->key, NULL);
128 ASSERT_INT_EQ(sshkey_equal(l->key, expected->l.key), 1);
131 if (parse_key && !(l->comment == NULL && expected->l.comment == NULL))
132 ASSERT_STRING_EQ(l->comment, expected->l.comment);
136 /* Loads public keys for a set of expected results */
138 prepare_expected(struct expected *expected, size_t n)
142 for (i = 0; i < n; i++) {
143 if (expected[i].key_file == NULL)
145 #ifndef OPENSSL_HAS_ECC
146 if (expected[i].l.keytype == KEY_ECDSA)
149 ASSERT_INT_EQ(sshkey_load_public(
150 test_data_file(expected[i].key_file), &expected[i].l.key,
155 struct expected expected_full[] = {
156 { NULL, -1, -1, 0, 0, 0, 0, -1, {
157 NULL, /* path, don't care */
159 HKF_STATUS_COMMENT, /* status */
161 "# Plain host keys, plain host names", /* full line, optional */
162 MRK_NONE, /* marker (CA / revoked) */
163 NULL, /* hosts text */
164 NULL, /* raw key, optional */
165 KEY_UNSPEC, /* key type */
166 NULL, /* deserialised key */
169 { "dsa_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
176 "sisyphus.example.com",
179 NULL, /* filled at runtime */
182 { "ecdsa_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
189 "sisyphus.example.com",
192 NULL, /* filled at runtime */
195 { "ed25519_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
202 "sisyphus.example.com",
205 NULL, /* filled at runtime */
208 { "rsa_1.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
215 "sisyphus.example.com",
218 NULL, /* filled at runtime */
221 { NULL, -1, -1, 0, 0, 0, 0, -1, {
234 { NULL, -1, -1, 0, 0, 0, 0, -1, {
239 "# Plain host keys, hostnames + addresses",
247 { "dsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
254 "prometheus.example.com,192.0.2.1,2001:db8::1",
257 NULL, /* filled at runtime */
260 { "ecdsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
267 "prometheus.example.com,192.0.2.1,2001:db8::1",
270 NULL, /* filled at runtime */
273 { "ed25519_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
280 "prometheus.example.com,192.0.2.1,2001:db8::1",
283 NULL, /* filled at runtime */
286 { "rsa_2.pub" , -1, -1, HKF_MATCH_HOST, 0, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
293 "prometheus.example.com,192.0.2.1,2001:db8::1",
296 NULL, /* filled at runtime */
299 { NULL, -1, -1, 0, 0, 0, 0, -1, {
312 { NULL, -1, -1, 0, 0, 0, 0, -1, {
317 "# Some hosts with wildcard names / IPs",
325 { "dsa_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
332 "*.example.com,192.0.2.*,2001:*",
335 NULL, /* filled at runtime */
338 { "ecdsa_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
345 "*.example.com,192.0.2.*,2001:*",
348 NULL, /* filled at runtime */
351 { "ed25519_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
358 "*.example.com,192.0.2.*,2001:*",
361 NULL, /* filled at runtime */
364 { "rsa_3.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, HKF_MATCH_IP, HKF_MATCH_IP, -1, {
371 "*.example.com,192.0.2.*,2001:*",
374 NULL, /* filled at runtime */
377 { NULL, -1, -1, 0, 0, 0, 0, -1, {
390 { NULL, -1, -1, 0, 0, 0, 0, -1, {
395 "# Hashed hostname and address entries",
403 { "dsa_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, {
413 NULL, /* filled at runtime */
416 { "ecdsa_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, {
426 NULL, /* filled at runtime */
429 { "ed25519_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, {
439 NULL, /* filled at runtime */
442 { "rsa_5.pub" , -1, -1, 0, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, -1, {
452 NULL, /* filled at runtime */
455 { NULL, -1, -1, 0, 0, 0, 0, -1, {
469 * The next series have each key listed multiple times, as the
470 * hostname and addresses in the pre-hashed known_hosts are split
473 { "dsa_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, {
483 NULL, /* filled at runtime */
486 { "dsa_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, {
496 NULL, /* filled at runtime */
499 { "dsa_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, {
509 NULL, /* filled at runtime */
512 { "ecdsa_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, {
522 NULL, /* filled at runtime */
525 { "ecdsa_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, {
535 NULL, /* filled at runtime */
538 { "ecdsa_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, {
548 NULL, /* filled at runtime */
551 { "ed25519_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, {
561 NULL, /* filled at runtime */
564 { "ed25519_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, {
574 NULL, /* filled at runtime */
577 { "ed25519_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, {
587 NULL, /* filled at runtime */
590 { "rsa_6.pub" , -1, -1, HKF_MATCH_HOST|HKF_MATCH_HOST_HASHED, 0, 0, 0, -1, {
600 NULL, /* filled at runtime */
603 { "rsa_6.pub" , -1, -1, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, 0, -1, {
613 NULL, /* filled at runtime */
616 { "rsa_6.pub" , -1, -1, 0, 0, 0, HKF_MATCH_IP|HKF_MATCH_IP_HASHED, -1, {
626 NULL, /* filled at runtime */
629 { NULL, -1, -1, 0, 0, 0, 0, -1, {
642 { NULL, -1, -1, 0, 0, 0, 0, -1, {
655 { NULL, -1, -1, 0, 0, 0, 0, -1, {
660 "# Revoked and CA keys",
668 { "ed25519_4.pub" , -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
675 "sisyphus.example.com",
678 NULL, /* filled at runtime */
681 { "ecdsa_4.pub" , -1, -1, HKF_MATCH_HOST, 0, 0, 0, -1, {
688 "prometheus.example.com",
691 NULL, /* filled at runtime */
694 { "dsa_4.pub" , -1, -1, HKF_MATCH_HOST, HKF_MATCH_HOST, 0, 0, -1, {
704 NULL, /* filled at runtime */
707 { NULL, -1, -1, 0, 0, 0, 0, -1, {
720 { NULL, -1, -1, 0, 0, 0, 0, -1, {
725 "# Some invalid lines",
733 { NULL, -1, -1, 0, 0, 0, 0, -1, {
746 { NULL, -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
753 "sisyphus.example.com",
759 { NULL, -1, -1, HKF_MATCH_HOST, 0, 0, 0, -1, {
766 "prometheus.example.com",
772 { NULL, -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
775 HKF_STATUS_INVALID, /* Would be ok if key not parsed */
779 "sisyphus.example.com",
785 { NULL, -1, -1, 0, HKF_MATCH_HOST, 0, 0, -1, {
792 "sisyphus.example.com",
795 NULL, /* filled at runtime */
798 { NULL, HKF_STATUS_OK, KEY_RSA, HKF_MATCH_HOST, 0, 0, 0, -1, {
801 HKF_STATUS_INVALID, /* Would be ok if key not parsed */
805 "prometheus.example.com",
808 NULL, /* filled at runtime */
813 void test_iterate(void);
820 TEST_START("hostkeys_iterate all with key parse");
821 memset(&ctx, 0, sizeof(ctx));
822 ctx.expected = expected_full;
823 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
824 ctx.flags = HKF_WANT_PARSE_KEY;
825 prepare_expected(expected_full, ctx.nexpected);
826 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
827 check, &ctx, NULL, NULL, ctx.flags), 0);
830 TEST_START("hostkeys_iterate all without key parse");
831 memset(&ctx, 0, sizeof(ctx));
832 ctx.expected = expected_full;
833 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
835 prepare_expected(expected_full, ctx.nexpected);
836 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
837 check, &ctx, NULL, NULL, ctx.flags), 0);
840 TEST_START("hostkeys_iterate specify host 1");
841 memset(&ctx, 0, sizeof(ctx));
842 ctx.expected = expected_full;
843 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
845 ctx.match_host_p = 1;
846 prepare_expected(expected_full, ctx.nexpected);
847 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
848 check, &ctx, "prometheus.example.com", NULL, ctx.flags), 0);
851 TEST_START("hostkeys_iterate specify host 2");
852 memset(&ctx, 0, sizeof(ctx));
853 ctx.expected = expected_full;
854 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
856 ctx.match_host_s = 1;
857 prepare_expected(expected_full, ctx.nexpected);
858 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
859 check, &ctx, "sisyphus.example.com", NULL, ctx.flags), 0);
862 TEST_START("hostkeys_iterate match host 1");
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 ctx.match_host_p = 1;
868 prepare_expected(expected_full, ctx.nexpected);
869 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
870 check, &ctx, "prometheus.example.com", NULL, ctx.flags), 0);
873 TEST_START("hostkeys_iterate match host 2");
874 memset(&ctx, 0, sizeof(ctx));
875 ctx.expected = expected_full;
876 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
877 ctx.flags = HKF_WANT_MATCH;
878 ctx.match_host_s = 1;
879 prepare_expected(expected_full, ctx.nexpected);
880 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
881 check, &ctx, "sisyphus.example.com", NULL, ctx.flags), 0);
884 TEST_START("hostkeys_iterate specify host missing");
885 memset(&ctx, 0, sizeof(ctx));
886 ctx.expected = expected_full;
887 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
889 prepare_expected(expected_full, ctx.nexpected);
890 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
891 check, &ctx, "actaeon.example.org", NULL, ctx.flags), 0);
894 TEST_START("hostkeys_iterate match host missing");
895 memset(&ctx, 0, sizeof(ctx));
896 ctx.expected = expected_full;
897 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
898 ctx.flags = HKF_WANT_MATCH;
899 prepare_expected(expected_full, ctx.nexpected);
900 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
901 check, &ctx, "actaeon.example.org", NULL, ctx.flags), 0);
904 TEST_START("hostkeys_iterate specify IPv4");
905 memset(&ctx, 0, sizeof(ctx));
906 ctx.expected = expected_full;
907 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
910 prepare_expected(expected_full, ctx.nexpected);
911 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
912 check, &ctx, "tiresias.example.org", "192.0.2.1", ctx.flags), 0);
915 TEST_START("hostkeys_iterate specify IPv6");
916 memset(&ctx, 0, sizeof(ctx));
917 ctx.expected = expected_full;
918 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
921 prepare_expected(expected_full, ctx.nexpected);
922 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
923 check, &ctx, "tiresias.example.org", "2001:db8::1", ctx.flags), 0);
926 TEST_START("hostkeys_iterate match IPv4");
927 memset(&ctx, 0, sizeof(ctx));
928 ctx.expected = expected_full;
929 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
930 ctx.flags = HKF_WANT_MATCH;
932 prepare_expected(expected_full, ctx.nexpected);
933 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
934 check, &ctx, "tiresias.example.org", "192.0.2.1", ctx.flags), 0);
937 TEST_START("hostkeys_iterate match IPv6");
938 memset(&ctx, 0, sizeof(ctx));
939 ctx.expected = expected_full;
940 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
941 ctx.flags = HKF_WANT_MATCH;
943 prepare_expected(expected_full, ctx.nexpected);
944 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
945 check, &ctx, "tiresias.example.org", "2001:db8::1", ctx.flags), 0);
948 TEST_START("hostkeys_iterate specify addr missing");
949 memset(&ctx, 0, sizeof(ctx));
950 ctx.expected = expected_full;
951 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
953 prepare_expected(expected_full, ctx.nexpected);
954 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
955 check, &ctx, "tiresias.example.org", "192.168.0.1", ctx.flags), 0);
958 TEST_START("hostkeys_iterate match addr missing");
959 memset(&ctx, 0, sizeof(ctx));
960 ctx.expected = expected_full;
961 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
962 ctx.flags = HKF_WANT_MATCH;
963 prepare_expected(expected_full, ctx.nexpected);
964 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
965 check, &ctx, "tiresias.example.org", "::1", ctx.flags), 0);
968 TEST_START("hostkeys_iterate specify host 2 and IPv4");
969 memset(&ctx, 0, sizeof(ctx));
970 ctx.expected = expected_full;
971 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
973 ctx.match_host_s = 1;
975 prepare_expected(expected_full, ctx.nexpected);
976 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
977 check, &ctx, "sisyphus.example.com", "192.0.2.1", ctx.flags), 0);
980 TEST_START("hostkeys_iterate match host 1 and IPv6");
981 memset(&ctx, 0, sizeof(ctx));
982 ctx.expected = expected_full;
983 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
984 ctx.flags = HKF_WANT_MATCH;
985 ctx.match_host_p = 1;
987 prepare_expected(expected_full, ctx.nexpected);
988 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
989 check, &ctx, "prometheus.example.com", "2001:db8::1", ctx.flags), 0);
992 TEST_START("hostkeys_iterate specify host 2 and IPv4 w/ key parse");
993 memset(&ctx, 0, sizeof(ctx));
994 ctx.expected = expected_full;
995 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
996 ctx.flags = HKF_WANT_PARSE_KEY;
997 ctx.match_host_s = 1;
999 prepare_expected(expected_full, ctx.nexpected);
1000 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
1001 check, &ctx, "sisyphus.example.com", "192.0.2.1", ctx.flags), 0);
1004 TEST_START("hostkeys_iterate match host 1 and IPv6 w/ key parse");
1005 memset(&ctx, 0, sizeof(ctx));
1006 ctx.expected = expected_full;
1007 ctx.nexpected = sizeof(expected_full)/sizeof(*expected_full);
1008 ctx.flags = HKF_WANT_MATCH|HKF_WANT_PARSE_KEY;
1009 ctx.match_host_p = 1;
1011 prepare_expected(expected_full, ctx.nexpected);
1012 ASSERT_INT_EQ(hostkeys_foreach(test_data_file("known_hosts"),
1013 check, &ctx, "prometheus.example.com", "2001:db8::1", ctx.flags), 0);