xref: /openbsd-src/regress/usr.bin/ssh/unittests/authopt/tests.c (revision a8c975d25b8973125837f3cd4c63b4a611f5c5f5)
1*a8c975d2Sderaadt /* 	$OpenBSD: tests.c,v 1.3 2021/12/14 21:25:27 deraadt Exp $ */
25e7798d9Sdjm 
35e7798d9Sdjm /*
45e7798d9Sdjm  * Regress test for keys options functions.
55e7798d9Sdjm  *
65e7798d9Sdjm  * Placed in the public domain
75e7798d9Sdjm  */
85e7798d9Sdjm 
95e7798d9Sdjm #include <sys/types.h>
105e7798d9Sdjm #include <stdio.h>
115e7798d9Sdjm #include <stdint.h>
125e7798d9Sdjm #include <stdlib.h>
135e7798d9Sdjm #include <string.h>
145e7798d9Sdjm 
155e7798d9Sdjm #include "test_helper.h"
165e7798d9Sdjm 
175e7798d9Sdjm #include "sshkey.h"
185e7798d9Sdjm #include "authfile.h"
195e7798d9Sdjm #include "auth-options.h"
205e7798d9Sdjm #include "misc.h"
215e7798d9Sdjm #include "log.h"
225e7798d9Sdjm 
235e7798d9Sdjm static struct sshkey *
load_key(const char * name)245e7798d9Sdjm load_key(const char *name)
255e7798d9Sdjm {
265e7798d9Sdjm 	struct sshkey *ret;
275e7798d9Sdjm 	int r;
285e7798d9Sdjm 
295e7798d9Sdjm 	r = sshkey_load_public(test_data_file(name), &ret, NULL);
305e7798d9Sdjm 	ASSERT_INT_EQ(r, 0);
315e7798d9Sdjm 	ASSERT_PTR_NE(ret, NULL);
325e7798d9Sdjm 	return ret;
335e7798d9Sdjm }
345e7798d9Sdjm 
355e7798d9Sdjm static struct sshauthopt *
default_authkey_opts(void)365e7798d9Sdjm default_authkey_opts(void)
375e7798d9Sdjm {
385e7798d9Sdjm 	struct sshauthopt *ret = sshauthopt_new();
395e7798d9Sdjm 
405e7798d9Sdjm 	ASSERT_PTR_NE(ret, NULL);
415e7798d9Sdjm 	ret->permit_port_forwarding_flag = 1;
425e7798d9Sdjm 	ret->permit_agent_forwarding_flag = 1;
435e7798d9Sdjm 	ret->permit_x11_forwarding_flag = 1;
445e7798d9Sdjm 	ret->permit_pty_flag = 1;
455e7798d9Sdjm 	ret->permit_user_rc = 1;
465e7798d9Sdjm 	return ret;
475e7798d9Sdjm }
485e7798d9Sdjm 
495e7798d9Sdjm static struct sshauthopt *
default_authkey_restrict_opts(void)505e7798d9Sdjm default_authkey_restrict_opts(void)
515e7798d9Sdjm {
525e7798d9Sdjm 	struct sshauthopt *ret = sshauthopt_new();
535e7798d9Sdjm 
545e7798d9Sdjm 	ASSERT_PTR_NE(ret, NULL);
555e7798d9Sdjm 	ret->permit_port_forwarding_flag = 0;
565e7798d9Sdjm 	ret->permit_agent_forwarding_flag = 0;
575e7798d9Sdjm 	ret->permit_x11_forwarding_flag = 0;
585e7798d9Sdjm 	ret->permit_pty_flag = 0;
595e7798d9Sdjm 	ret->permit_user_rc = 0;
605e7798d9Sdjm 	ret->restricted = 1;
615e7798d9Sdjm 	return ret;
625e7798d9Sdjm }
635e7798d9Sdjm 
645e7798d9Sdjm static char **
commasplit(const char * s,size_t * np)655e7798d9Sdjm commasplit(const char *s, size_t *np)
665e7798d9Sdjm {
675e7798d9Sdjm 	char *ocp, *cp, *cp2, **ret = NULL;
685e7798d9Sdjm 	size_t n;
695e7798d9Sdjm 
705e7798d9Sdjm 	ocp = cp = strdup(s);
715e7798d9Sdjm 	ASSERT_PTR_NE(cp, NULL);
725e7798d9Sdjm 	for (n = 0; (cp2 = strsep(&cp, ",")) != NULL;) {
735e7798d9Sdjm 		ret = recallocarray(ret, n, n + 1, sizeof(*ret));
745e7798d9Sdjm 		ASSERT_PTR_NE(ret, NULL);
755e7798d9Sdjm 		cp2 = strdup(cp2);
765e7798d9Sdjm 		ASSERT_PTR_NE(cp2, NULL);
775e7798d9Sdjm 		ret[n++] = cp2;
785e7798d9Sdjm 	}
795e7798d9Sdjm 	free(ocp);
805e7798d9Sdjm 	*np = n;
815e7798d9Sdjm 	return ret;
825e7798d9Sdjm }
835e7798d9Sdjm 
845e7798d9Sdjm static void
compare_opts(const struct sshauthopt * opts,const struct sshauthopt * expected)855e7798d9Sdjm compare_opts(const struct sshauthopt *opts,
865e7798d9Sdjm     const struct sshauthopt *expected)
875e7798d9Sdjm {
885e7798d9Sdjm 	size_t i;
895e7798d9Sdjm 
905e7798d9Sdjm 	ASSERT_PTR_NE(opts, NULL);
915e7798d9Sdjm 	ASSERT_PTR_NE(expected, NULL);
925e7798d9Sdjm 	ASSERT_PTR_NE(expected, opts); /* bozo :) */
935e7798d9Sdjm 
945e7798d9Sdjm #define FLAG_EQ(x) ASSERT_INT_EQ(opts->x, expected->x)
955e7798d9Sdjm 	FLAG_EQ(permit_port_forwarding_flag);
965e7798d9Sdjm 	FLAG_EQ(permit_agent_forwarding_flag);
975e7798d9Sdjm 	FLAG_EQ(permit_x11_forwarding_flag);
985e7798d9Sdjm 	FLAG_EQ(permit_pty_flag);
995e7798d9Sdjm 	FLAG_EQ(permit_user_rc);
1005e7798d9Sdjm 	FLAG_EQ(restricted);
1015e7798d9Sdjm 	FLAG_EQ(cert_authority);
1025e7798d9Sdjm #undef FLAG_EQ
1035e7798d9Sdjm 
1045e7798d9Sdjm #define STR_EQ(x) \
1055e7798d9Sdjm 	do { \
1065e7798d9Sdjm 		if (expected->x == NULL) \
1075e7798d9Sdjm 			ASSERT_PTR_EQ(opts->x, expected->x); \
1085e7798d9Sdjm 		else \
1095e7798d9Sdjm 			ASSERT_STRING_EQ(opts->x, expected->x); \
1105e7798d9Sdjm 	} while (0)
1115e7798d9Sdjm 	STR_EQ(cert_principals);
1125e7798d9Sdjm 	STR_EQ(force_command);
1135e7798d9Sdjm 	STR_EQ(required_from_host_cert);
1145e7798d9Sdjm 	STR_EQ(required_from_host_keys);
1155e7798d9Sdjm #undef STR_EQ
1165e7798d9Sdjm 
1175e7798d9Sdjm #define ARRAY_EQ(nx, x) \
1185e7798d9Sdjm 	do { \
1195e7798d9Sdjm 		ASSERT_SIZE_T_EQ(opts->nx, expected->nx); \
1205e7798d9Sdjm 		if (expected->nx == 0) \
1215e7798d9Sdjm 			break; \
1225e7798d9Sdjm 		for (i = 0; i < expected->nx; i++) \
1235e7798d9Sdjm 			ASSERT_STRING_EQ(opts->x[i], expected->x[i]); \
1245e7798d9Sdjm 	} while (0)
1255e7798d9Sdjm 	ARRAY_EQ(nenv, env);
1265e7798d9Sdjm 	ARRAY_EQ(npermitopen, permitopen);
1275e7798d9Sdjm #undef ARRAY_EQ
1285e7798d9Sdjm }
1295e7798d9Sdjm 
1305e7798d9Sdjm static void
test_authkeys_parse(void)1315e7798d9Sdjm test_authkeys_parse(void)
1325e7798d9Sdjm {
1335e7798d9Sdjm 	struct sshauthopt *opts, *expected;
1345e7798d9Sdjm 	const char *errstr;
1355e7798d9Sdjm 
1365e7798d9Sdjm #define FAIL_TEST(label, keywords) \
1375e7798d9Sdjm 	do { \
1385e7798d9Sdjm 		TEST_START("sshauthopt_parse invalid " label); \
1395e7798d9Sdjm 		opts = sshauthopt_parse(keywords, &errstr); \
1405e7798d9Sdjm 		ASSERT_PTR_EQ(opts, NULL); \
1415e7798d9Sdjm 		ASSERT_PTR_NE(errstr, NULL); \
1425e7798d9Sdjm 		TEST_DONE(); \
1435e7798d9Sdjm 	} while (0)
1445e7798d9Sdjm #define CHECK_SUCCESS_AND_CLEANUP() \
1455e7798d9Sdjm 	do { \
1465e7798d9Sdjm 		if (errstr != NULL) \
1475e7798d9Sdjm 			ASSERT_STRING_EQ(errstr, ""); \
1485e7798d9Sdjm 		compare_opts(opts, expected); \
1495e7798d9Sdjm 		sshauthopt_free(expected); \
1505e7798d9Sdjm 		sshauthopt_free(opts); \
1515e7798d9Sdjm 	} while (0)
1525e7798d9Sdjm 
1535e7798d9Sdjm 	/* Basic tests */
1545e7798d9Sdjm 	TEST_START("sshauthopt_parse empty");
1555e7798d9Sdjm 	expected = default_authkey_opts();
1565e7798d9Sdjm 	opts = sshauthopt_parse("", &errstr);
1575e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
1585e7798d9Sdjm 	TEST_DONE();
1595e7798d9Sdjm 
1605e7798d9Sdjm 	TEST_START("sshauthopt_parse trailing whitespace");
1615e7798d9Sdjm 	expected = default_authkey_opts();
1625e7798d9Sdjm 	opts = sshauthopt_parse(" ", &errstr);
1635e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
1645e7798d9Sdjm 	TEST_DONE();
1655e7798d9Sdjm 
1665e7798d9Sdjm 	TEST_START("sshauthopt_parse restrict");
1675e7798d9Sdjm 	expected = default_authkey_restrict_opts();
1685e7798d9Sdjm 	opts = sshauthopt_parse("restrict", &errstr);
1695e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
1705e7798d9Sdjm 	TEST_DONE();
1715e7798d9Sdjm 
1725e7798d9Sdjm 	/* Invalid syntax */
1735e7798d9Sdjm 	FAIL_TEST("trailing comma", "restrict,");
1745e7798d9Sdjm 	FAIL_TEST("bare comma", ",");
1755e7798d9Sdjm 	FAIL_TEST("unknown option", "BLAH");
1765e7798d9Sdjm 	FAIL_TEST("unknown option with trailing comma", "BLAH,");
1775e7798d9Sdjm 	FAIL_TEST("unknown option with trailing whitespace", "BLAH ");
1785e7798d9Sdjm 
1795e7798d9Sdjm 	/* force_tun_device */
1805e7798d9Sdjm 	TEST_START("sshauthopt_parse tunnel explicit");
1815e7798d9Sdjm 	expected = default_authkey_opts();
1825e7798d9Sdjm 	expected->force_tun_device = 1;
1835e7798d9Sdjm 	opts = sshauthopt_parse("tunnel=\"1\"", &errstr);
1845e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
1855e7798d9Sdjm 	TEST_DONE();
1865e7798d9Sdjm 
1875e7798d9Sdjm 	TEST_START("sshauthopt_parse tunnel any");
1885e7798d9Sdjm 	expected = default_authkey_opts();
1895e7798d9Sdjm 	expected->force_tun_device = SSH_TUNID_ANY;
1905e7798d9Sdjm 	opts = sshauthopt_parse("tunnel=\"any\"", &errstr);
1915e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
1925e7798d9Sdjm 	TEST_DONE();
1935e7798d9Sdjm 
1945e7798d9Sdjm 	FAIL_TEST("tunnel", "tunnel=\"blah\"");
1955e7798d9Sdjm 
1965e7798d9Sdjm 	/* Flag options */
1975e7798d9Sdjm #define FLAG_TEST(keyword, var, val) \
1985e7798d9Sdjm 	do { \
1995e7798d9Sdjm 		TEST_START("sshauthopt_parse " keyword); \
2005e7798d9Sdjm 		expected = default_authkey_opts(); \
2015e7798d9Sdjm 		expected->var = val; \
2025e7798d9Sdjm 		opts = sshauthopt_parse(keyword, &errstr); \
2035e7798d9Sdjm 		CHECK_SUCCESS_AND_CLEANUP(); \
2045e7798d9Sdjm 		expected = default_authkey_restrict_opts(); \
2055e7798d9Sdjm 		expected->var = val; \
2065e7798d9Sdjm 		opts = sshauthopt_parse("restrict,"keyword, &errstr); \
2075e7798d9Sdjm 		CHECK_SUCCESS_AND_CLEANUP(); \
2085e7798d9Sdjm 		TEST_DONE(); \
2095e7798d9Sdjm 	} while (0)
2105e7798d9Sdjm 	/* Positive flags */
2115e7798d9Sdjm 	FLAG_TEST("cert-authority", cert_authority, 1);
2125e7798d9Sdjm 	FLAG_TEST("port-forwarding", permit_port_forwarding_flag, 1);
2135e7798d9Sdjm 	FLAG_TEST("agent-forwarding", permit_agent_forwarding_flag, 1);
2145e7798d9Sdjm 	FLAG_TEST("x11-forwarding", permit_x11_forwarding_flag, 1);
2155e7798d9Sdjm 	FLAG_TEST("pty", permit_pty_flag, 1);
2165e7798d9Sdjm 	FLAG_TEST("user-rc", permit_user_rc, 1);
2175e7798d9Sdjm 	/* Negative flags */
2185e7798d9Sdjm 	FLAG_TEST("no-port-forwarding", permit_port_forwarding_flag, 0);
2195e7798d9Sdjm 	FLAG_TEST("no-agent-forwarding", permit_agent_forwarding_flag, 0);
2205e7798d9Sdjm 	FLAG_TEST("no-x11-forwarding", permit_x11_forwarding_flag, 0);
2215e7798d9Sdjm 	FLAG_TEST("no-pty", permit_pty_flag, 0);
2225e7798d9Sdjm 	FLAG_TEST("no-user-rc", permit_user_rc, 0);
2235e7798d9Sdjm #undef FLAG_TEST
2245e7798d9Sdjm 	FAIL_TEST("no-cert-authority", "no-cert-authority");
2255e7798d9Sdjm 
2265e7798d9Sdjm 	/* String options */
2275e7798d9Sdjm #define STRING_TEST(keyword, var, val) \
2285e7798d9Sdjm 	do { \
2295e7798d9Sdjm 		TEST_START("sshauthopt_parse " keyword); \
2305e7798d9Sdjm 		expected = default_authkey_opts(); \
2315e7798d9Sdjm 		expected->var = strdup(val); \
2325e7798d9Sdjm 		ASSERT_PTR_NE(expected->var, NULL); \
2335e7798d9Sdjm 		opts = sshauthopt_parse(keyword "=" #val, &errstr); \
2345e7798d9Sdjm 		CHECK_SUCCESS_AND_CLEANUP(); \
2355e7798d9Sdjm 		expected = default_authkey_restrict_opts(); \
2365e7798d9Sdjm 		expected->var = strdup(val); \
2375e7798d9Sdjm 		ASSERT_PTR_NE(expected->var, NULL); \
2385e7798d9Sdjm 		opts = sshauthopt_parse( \
2395e7798d9Sdjm 		    "restrict," keyword "=" #val ",restrict", &errstr); \
2405e7798d9Sdjm 		CHECK_SUCCESS_AND_CLEANUP(); \
2415e7798d9Sdjm 		TEST_DONE(); \
2425e7798d9Sdjm 	} while (0)
2435e7798d9Sdjm 	STRING_TEST("command", force_command, "/bin/true");
2445e7798d9Sdjm 	STRING_TEST("principals", cert_principals, "gregor,josef,K");
2455e7798d9Sdjm 	STRING_TEST("from", required_from_host_keys, "127.0.0.0/8");
2465e7798d9Sdjm #undef STRING_TEST
2475e7798d9Sdjm 	FAIL_TEST("unquoted command", "command=oops");
2485e7798d9Sdjm 	FAIL_TEST("unquoted principals", "principals=estragon");
2495e7798d9Sdjm 	FAIL_TEST("unquoted from", "from=127.0.0.1");
2505e7798d9Sdjm 
2515e7798d9Sdjm 	/* String array option tests */
2525e7798d9Sdjm #define ARRAY_TEST(label, keywords, var, nvar, val) \
2535e7798d9Sdjm 	do { \
2545e7798d9Sdjm 		TEST_START("sshauthopt_parse " label); \
2555e7798d9Sdjm 		expected = default_authkey_opts(); \
2565e7798d9Sdjm 		expected->var = commasplit(val, &expected->nvar); \
2575e7798d9Sdjm 		ASSERT_PTR_NE(expected->var, NULL); \
2585e7798d9Sdjm 		opts = sshauthopt_parse(keywords, &errstr); \
2595e7798d9Sdjm 		CHECK_SUCCESS_AND_CLEANUP(); \
2605e7798d9Sdjm 		expected = default_authkey_restrict_opts(); \
2615e7798d9Sdjm 		expected->var = commasplit(val, &expected->nvar); \
2625e7798d9Sdjm 		ASSERT_PTR_NE(expected->var, NULL); \
2635e7798d9Sdjm 		opts = sshauthopt_parse( \
2645e7798d9Sdjm 		    "restrict," keywords ",restrict", &errstr); \
2655e7798d9Sdjm 		CHECK_SUCCESS_AND_CLEANUP(); \
2665e7798d9Sdjm 		TEST_DONE(); \
2675e7798d9Sdjm 	} while (0)
2685e7798d9Sdjm 	ARRAY_TEST("environment", "environment=\"foo=1\",environment=\"bar=2\"",
2695e7798d9Sdjm 	    env, nenv, "foo=1,bar=2");
2706631e68bSdjm 	ARRAY_TEST("environment", "environment=\"foo=1\",environment=\"foo=2\"",
2716631e68bSdjm 	    env, nenv, "foo=1");
2725e7798d9Sdjm 	ARRAY_TEST("permitopen", "permitopen=\"foo:123\",permitopen=\"bar:*\"",
2735e7798d9Sdjm 	    permitopen, npermitopen, "foo:123,bar:*");
2745e7798d9Sdjm #undef ARRAY_TEST
2755e7798d9Sdjm 	FAIL_TEST("environment", "environment=\",=bah\"");
2765e7798d9Sdjm 	FAIL_TEST("permitopen port", "foo:bar");
2775e7798d9Sdjm 	FAIL_TEST("permitopen missing port", "foo:");
2785e7798d9Sdjm 	FAIL_TEST("permitopen missing port specification", "foo");
2795e7798d9Sdjm 	FAIL_TEST("permitopen invalid host", "[:");
2805e7798d9Sdjm 
2815e7798d9Sdjm #undef CHECK_SUCCESS_AND_CLEANUP
2825e7798d9Sdjm #undef FAIL_TEST
2835e7798d9Sdjm }
2845e7798d9Sdjm 
2855e7798d9Sdjm static void
test_cert_parse(void)2865e7798d9Sdjm test_cert_parse(void)
2875e7798d9Sdjm {
2885e7798d9Sdjm 	struct sshkey *cert;
2895e7798d9Sdjm 	struct sshauthopt *opts, *expected;
2905e7798d9Sdjm 
2915e7798d9Sdjm #define CHECK_SUCCESS_AND_CLEANUP() \
2925e7798d9Sdjm 	do { \
2935e7798d9Sdjm 		compare_opts(opts, expected); \
2945e7798d9Sdjm 		sshauthopt_free(expected); \
2955e7798d9Sdjm 		sshauthopt_free(opts); \
2965e7798d9Sdjm 		sshkey_free(cert); \
2975e7798d9Sdjm 	} while (0)
2985e7798d9Sdjm #define FLAG_TEST(keybase, var) \
2995e7798d9Sdjm 	do { \
3005e7798d9Sdjm 		TEST_START("sshauthopt_from_cert no_" keybase); \
3015e7798d9Sdjm 		cert = load_key("no_" keybase ".cert"); \
3025e7798d9Sdjm 		expected = default_authkey_opts(); \
3035e7798d9Sdjm 		expected->var = 0; \
3045e7798d9Sdjm 		opts = sshauthopt_from_cert(cert); \
3055e7798d9Sdjm 		CHECK_SUCCESS_AND_CLEANUP(); \
3065e7798d9Sdjm 		TEST_DONE(); \
3075e7798d9Sdjm 		TEST_START("sshauthopt_from_cert only_" keybase); \
3085e7798d9Sdjm 		cert = load_key("only_" keybase ".cert"); \
3095e7798d9Sdjm 		expected = sshauthopt_new(); \
3105e7798d9Sdjm 		ASSERT_PTR_NE(expected, NULL); \
3115e7798d9Sdjm 		expected->var = 1; \
3125e7798d9Sdjm 		opts = sshauthopt_from_cert(cert); \
3135e7798d9Sdjm 		CHECK_SUCCESS_AND_CLEANUP(); \
3145e7798d9Sdjm 		TEST_DONE(); \
3155e7798d9Sdjm 	} while (0)
3165e7798d9Sdjm 	FLAG_TEST("agentfwd", permit_agent_forwarding_flag);
3175e7798d9Sdjm 	FLAG_TEST("portfwd", permit_port_forwarding_flag);
3185e7798d9Sdjm 	FLAG_TEST("pty", permit_pty_flag);
3195e7798d9Sdjm 	FLAG_TEST("user_rc", permit_user_rc);
3205e7798d9Sdjm 	FLAG_TEST("x11fwd", permit_x11_forwarding_flag);
3215e7798d9Sdjm #undef FLAG_TEST
3225e7798d9Sdjm 
3235e7798d9Sdjm 	TEST_START("sshauthopt_from_cert all permitted");
3245e7798d9Sdjm 	cert = load_key("all_permit.cert");
3255e7798d9Sdjm 	expected = default_authkey_opts();
3265e7798d9Sdjm 	opts = sshauthopt_from_cert(cert);
3275e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
3285e7798d9Sdjm 	TEST_DONE();
3295e7798d9Sdjm 
3305e7798d9Sdjm 	TEST_START("sshauthopt_from_cert nothing permitted");
3315e7798d9Sdjm 	cert = load_key("no_permit.cert");
3325e7798d9Sdjm 	expected = sshauthopt_new();
3335e7798d9Sdjm 	ASSERT_PTR_NE(expected, NULL);
3345e7798d9Sdjm 	opts = sshauthopt_from_cert(cert);
3355e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
3365e7798d9Sdjm 	TEST_DONE();
3375e7798d9Sdjm 
3385e7798d9Sdjm 	TEST_START("sshauthopt_from_cert force-command");
3395e7798d9Sdjm 	cert = load_key("force_command.cert");
3405e7798d9Sdjm 	expected = default_authkey_opts();
3415e7798d9Sdjm 	expected->force_command = strdup("foo");
3425e7798d9Sdjm 	ASSERT_PTR_NE(expected->force_command, NULL);
3435e7798d9Sdjm 	opts = sshauthopt_from_cert(cert);
3445e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
3455e7798d9Sdjm 	TEST_DONE();
3465e7798d9Sdjm 
3475e7798d9Sdjm 	TEST_START("sshauthopt_from_cert source-address");
3485e7798d9Sdjm 	cert = load_key("sourceaddr.cert");
3495e7798d9Sdjm 	expected = default_authkey_opts();
3505e7798d9Sdjm 	expected->required_from_host_cert = strdup("127.0.0.1/32,::1/128");
3515e7798d9Sdjm 	ASSERT_PTR_NE(expected->required_from_host_cert, NULL);
3525e7798d9Sdjm 	opts = sshauthopt_from_cert(cert);
3535e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
3545e7798d9Sdjm 	TEST_DONE();
3555e7798d9Sdjm #undef CHECK_SUCCESS_AND_CLEANUP
3565e7798d9Sdjm 
3575e7798d9Sdjm #define FAIL_TEST(keybase) \
3585e7798d9Sdjm 	do { \
3595e7798d9Sdjm 		TEST_START("sshauthopt_from_cert " keybase); \
3605e7798d9Sdjm 		cert = load_key(keybase ".cert"); \
3615e7798d9Sdjm 		opts = sshauthopt_from_cert(cert); \
3625e7798d9Sdjm 		ASSERT_PTR_EQ(opts, NULL); \
3635e7798d9Sdjm 		sshkey_free(cert); \
3645e7798d9Sdjm 		TEST_DONE(); \
3655e7798d9Sdjm 	} while (0)
3665e7798d9Sdjm 	FAIL_TEST("host");
3675e7798d9Sdjm 	FAIL_TEST("bad_sourceaddr");
3685e7798d9Sdjm 	FAIL_TEST("unknown_critical");
3695e7798d9Sdjm #undef FAIL_TEST
3705e7798d9Sdjm }
3715e7798d9Sdjm 
3725e7798d9Sdjm static void
test_merge(void)3735e7798d9Sdjm test_merge(void)
3745e7798d9Sdjm {
3755e7798d9Sdjm 	struct sshkey *cert;
3765e7798d9Sdjm 	struct sshauthopt *key_opts, *cert_opts, *merge_opts, *expected;
3775e7798d9Sdjm 	const char *errstr;
3785e7798d9Sdjm 
3795e7798d9Sdjm 	/*
3805e7798d9Sdjm 	 * Prepare for a test by making some key and cert options and
3815e7798d9Sdjm 	 * attempting to merge them.
3825e7798d9Sdjm 	 */
3835e7798d9Sdjm #define PREPARE(label, keyname, keywords) \
3845e7798d9Sdjm 	do { \
3855e7798d9Sdjm 		expected = NULL; \
3865e7798d9Sdjm 		TEST_START("sshauthopt_merge " label); \
3875e7798d9Sdjm 		cert = load_key(keyname ".cert"); \
3885e7798d9Sdjm 		cert_opts = sshauthopt_from_cert(cert); \
3895e7798d9Sdjm 		ASSERT_PTR_NE(cert_opts, NULL); \
3905e7798d9Sdjm 		key_opts = sshauthopt_parse(keywords, &errstr); \
3915e7798d9Sdjm 		if (errstr != NULL) \
3925e7798d9Sdjm 			ASSERT_STRING_EQ(errstr, ""); \
3935e7798d9Sdjm 		ASSERT_PTR_NE(key_opts, NULL); \
3945e7798d9Sdjm 		merge_opts = sshauthopt_merge(key_opts, \
3955e7798d9Sdjm 		    cert_opts, &errstr); \
3965e7798d9Sdjm 	} while (0)
3975e7798d9Sdjm 
3985e7798d9Sdjm 	/* Cleanup stuff allocated by PREPARE() */
3995e7798d9Sdjm #define CLEANUP() \
4005e7798d9Sdjm 	do { \
4015e7798d9Sdjm 		sshauthopt_free(expected); \
4025e7798d9Sdjm 		sshauthopt_free(merge_opts); \
4035e7798d9Sdjm 		sshauthopt_free(key_opts); \
4045e7798d9Sdjm 		sshauthopt_free(cert_opts); \
4055e7798d9Sdjm 		sshkey_free(cert); \
4065e7798d9Sdjm 	} while (0)
4075e7798d9Sdjm 
4085e7798d9Sdjm 	/* Check the results of PREPARE() against expectation; calls CLEANUP */
4095e7798d9Sdjm #define CHECK_SUCCESS_AND_CLEANUP() \
4105e7798d9Sdjm 	do { \
4115e7798d9Sdjm 		if (errstr != NULL) \
4125e7798d9Sdjm 			ASSERT_STRING_EQ(errstr, ""); \
4135e7798d9Sdjm 		compare_opts(merge_opts, expected); \
4145e7798d9Sdjm 		CLEANUP(); \
4155e7798d9Sdjm 	} while (0)
4165e7798d9Sdjm 
4175e7798d9Sdjm 	/* Check a single case of merging of flag options */
4185e7798d9Sdjm #define FLAG_CASE(keybase, label, keyname, keywords, mostly_off, var, val) \
4195e7798d9Sdjm 	do { \
4205e7798d9Sdjm 		PREPARE(keybase " " label, keyname, keywords); \
4215e7798d9Sdjm 		expected = mostly_off ? \
4225e7798d9Sdjm 		    sshauthopt_new() : default_authkey_opts(); \
4235e7798d9Sdjm 		expected->var = val; \
4245e7798d9Sdjm 		ASSERT_PTR_NE(expected, NULL); \
4255e7798d9Sdjm 		CHECK_SUCCESS_AND_CLEANUP(); \
4265e7798d9Sdjm 		TEST_DONE(); \
4275e7798d9Sdjm 	} while (0)
4285e7798d9Sdjm 
4295e7798d9Sdjm 	/*
4305e7798d9Sdjm 	 * Fairly exhaustive exercise of a flag option. Tests
4315e7798d9Sdjm 	 * option both set and clear in certificate, set and clear in
4325e7798d9Sdjm 	 * authorized_keys and set and cleared via restrict keyword.
4335e7798d9Sdjm 	 */
4345e7798d9Sdjm #define FLAG_TEST(keybase, keyword, var) \
4355e7798d9Sdjm 	do { \
4365e7798d9Sdjm 		FLAG_CASE(keybase, "keys:default,yes cert:default,no", \
4375e7798d9Sdjm 		    "no_" keybase, keyword, 0, var, 0); \
4385e7798d9Sdjm 		FLAG_CASE(keybase,"keys:-*,yes cert:default,no", \
4395e7798d9Sdjm 		    "no_" keybase, "restrict," keyword, 1, var, 0); \
4405e7798d9Sdjm 		FLAG_CASE(keybase, "keys:default,no cert:default,no", \
4415e7798d9Sdjm 		    "no_" keybase, "no-" keyword, 0, var, 0); \
4425e7798d9Sdjm 		FLAG_CASE(keybase, "keys:-*,no cert:default,no", \
4435e7798d9Sdjm 		    "no_" keybase, "restrict,no-" keyword, 1, var, 0); \
4445e7798d9Sdjm 		\
4455e7798d9Sdjm 		FLAG_CASE(keybase, "keys:default,yes cert:-*,yes", \
4465e7798d9Sdjm 		    "only_" keybase, keyword, 1, var, 1); \
4475e7798d9Sdjm 		FLAG_CASE(keybase,"keys:-*,yes cert:-*,yes", \
4485e7798d9Sdjm 		    "only_" keybase, "restrict," keyword, 1, var, 1); \
4495e7798d9Sdjm 		FLAG_CASE(keybase, "keys:default,no cert:-*,yes", \
4505e7798d9Sdjm 		    "only_" keybase, "no-" keyword, 1, var, 0); \
4515e7798d9Sdjm 		FLAG_CASE(keybase, "keys:-*,no cert:-*,yes", \
4525e7798d9Sdjm 		    "only_" keybase, "restrict,no-" keyword, 1, var, 0); \
4535e7798d9Sdjm 		\
4545e7798d9Sdjm 		FLAG_CASE(keybase, "keys:default,yes cert:-*", \
4555e7798d9Sdjm 		    "no_permit", keyword, 1, var, 0); \
4565e7798d9Sdjm 		FLAG_CASE(keybase,"keys:-*,yes cert:-*", \
4575e7798d9Sdjm 		    "no_permit", "restrict," keyword, 1, var, 0); \
4585e7798d9Sdjm 		FLAG_CASE(keybase, "keys:default,no cert:-*", \
4595e7798d9Sdjm 		    "no_permit", "no-" keyword, 1, var, 0); \
4605e7798d9Sdjm 		FLAG_CASE(keybase, "keys:-*,no cert:-*", \
4615e7798d9Sdjm 		    "no_permit", "restrict,no-" keyword, 1, var, 0); \
4625e7798d9Sdjm 		\
4635e7798d9Sdjm 		FLAG_CASE(keybase, "keys:default,yes cert:*", \
4645e7798d9Sdjm 		    "all_permit", keyword, 0, var, 1); \
4655e7798d9Sdjm 		FLAG_CASE(keybase,"keys:-*,yes cert:*", \
4665e7798d9Sdjm 		    "all_permit", "restrict," keyword, 1, var, 1); \
4675e7798d9Sdjm 		FLAG_CASE(keybase, "keys:default,no cert:*", \
4685e7798d9Sdjm 		    "all_permit", "no-" keyword, 0, var, 0); \
4695e7798d9Sdjm 		FLAG_CASE(keybase, "keys:-*,no cert:*", \
4705e7798d9Sdjm 		    "all_permit", "restrict,no-" keyword, 1, var, 0); \
4715e7798d9Sdjm 		\
4725e7798d9Sdjm 	} while (0)
4735e7798d9Sdjm 	FLAG_TEST("portfwd", "port-forwarding", permit_port_forwarding_flag);
4745e7798d9Sdjm 	FLAG_TEST("agentfwd", "agent-forwarding", permit_agent_forwarding_flag);
4755e7798d9Sdjm 	FLAG_TEST("pty", "pty", permit_pty_flag);
4765e7798d9Sdjm 	FLAG_TEST("user_rc", "user-rc", permit_user_rc);
4775e7798d9Sdjm 	FLAG_TEST("x11fwd", "x11-forwarding", permit_x11_forwarding_flag);
4785e7798d9Sdjm #undef FLAG_TEST
4795e7798d9Sdjm 
4805e7798d9Sdjm 	PREPARE("source-address both", "sourceaddr", "from=\"127.0.0.1\"");
4815e7798d9Sdjm 	expected = default_authkey_opts();
4825e7798d9Sdjm 	expected->required_from_host_cert = strdup("127.0.0.1/32,::1/128");
4835e7798d9Sdjm 	ASSERT_PTR_NE(expected->required_from_host_cert, NULL);
4845e7798d9Sdjm 	expected->required_from_host_keys = strdup("127.0.0.1");
4855e7798d9Sdjm 	ASSERT_PTR_NE(expected->required_from_host_keys, NULL);
4865e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
4875e7798d9Sdjm 	TEST_DONE();
4885e7798d9Sdjm 
4895e7798d9Sdjm 	PREPARE("source-address none", "all_permit", "");
4905e7798d9Sdjm 	expected = default_authkey_opts();
4915e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
4925e7798d9Sdjm 	TEST_DONE();
4935e7798d9Sdjm 
4945e7798d9Sdjm 	PREPARE("source-address keys", "all_permit", "from=\"127.0.0.1\"");
4955e7798d9Sdjm 	expected = default_authkey_opts();
4965e7798d9Sdjm 	expected->required_from_host_keys = strdup("127.0.0.1");
4975e7798d9Sdjm 	ASSERT_PTR_NE(expected->required_from_host_keys, NULL);
4985e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
4995e7798d9Sdjm 	TEST_DONE();
5005e7798d9Sdjm 
5015e7798d9Sdjm 	PREPARE("source-address cert", "sourceaddr", "");
5025e7798d9Sdjm 	expected = default_authkey_opts();
5035e7798d9Sdjm 	expected->required_from_host_cert = strdup("127.0.0.1/32,::1/128");
5045e7798d9Sdjm 	ASSERT_PTR_NE(expected->required_from_host_cert, NULL);
5055e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
5065e7798d9Sdjm 	TEST_DONE();
5075e7798d9Sdjm 
5085e7798d9Sdjm 	PREPARE("force-command both", "force_command", "command=\"foo\"");
5095e7798d9Sdjm 	expected = default_authkey_opts();
5105e7798d9Sdjm 	expected->force_command = strdup("foo");
5115e7798d9Sdjm 	ASSERT_PTR_NE(expected->force_command, NULL);
5125e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
5135e7798d9Sdjm 	TEST_DONE();
5145e7798d9Sdjm 
5155e7798d9Sdjm 	PREPARE("force-command none", "all_permit", "");
5165e7798d9Sdjm 	expected = default_authkey_opts();
5175e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
5185e7798d9Sdjm 	TEST_DONE();
5195e7798d9Sdjm 
5205e7798d9Sdjm 	PREPARE("force-command keys", "all_permit", "command=\"bar\"");
5215e7798d9Sdjm 	expected = default_authkey_opts();
5225e7798d9Sdjm 	expected->force_command = strdup("bar");
5235e7798d9Sdjm 	ASSERT_PTR_NE(expected->force_command, NULL);
5245e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
5255e7798d9Sdjm 	TEST_DONE();
5265e7798d9Sdjm 
5275e7798d9Sdjm 	PREPARE("force-command cert", "force_command", "");
5285e7798d9Sdjm 	expected = default_authkey_opts();
5295e7798d9Sdjm 	expected->force_command = strdup("foo");
5305e7798d9Sdjm 	ASSERT_PTR_NE(expected->force_command, NULL);
5315e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
5325e7798d9Sdjm 	TEST_DONE();
5335e7798d9Sdjm 
5345e7798d9Sdjm 	PREPARE("force-command mismatch", "force_command", "command=\"bar\"");
5355e7798d9Sdjm 	ASSERT_PTR_EQ(merge_opts, NULL);
5365e7798d9Sdjm 	CLEANUP();
5375e7798d9Sdjm 	TEST_DONE();
5385e7798d9Sdjm 
5395e7798d9Sdjm 	PREPARE("tunnel", "all_permit", "tunnel=\"6\"");
5405e7798d9Sdjm 	expected = default_authkey_opts();
5415e7798d9Sdjm 	expected->force_tun_device = 6;
5425e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
5435e7798d9Sdjm 	TEST_DONE();
5445e7798d9Sdjm 
5455e7798d9Sdjm 	PREPARE("permitopen", "all_permit",
5465e7798d9Sdjm 	    "permitopen=\"127.0.0.1:*\",permitopen=\"127.0.0.1:123\"");
5475e7798d9Sdjm 	expected = default_authkey_opts();
5485e7798d9Sdjm 	expected->permitopen = commasplit("127.0.0.1:*,127.0.0.1:123",
5495e7798d9Sdjm 	    &expected->npermitopen);
5505e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
5515e7798d9Sdjm 	TEST_DONE();
5525e7798d9Sdjm 
5535e7798d9Sdjm 	PREPARE("environment", "all_permit",
5545e7798d9Sdjm 	    "environment=\"foo=a\",environment=\"bar=b\"");
5555e7798d9Sdjm 	expected = default_authkey_opts();
5565e7798d9Sdjm 	expected->env = commasplit("foo=a,bar=b", &expected->nenv);
5575e7798d9Sdjm 	CHECK_SUCCESS_AND_CLEANUP();
5585e7798d9Sdjm 	TEST_DONE();
5595e7798d9Sdjm }
5605e7798d9Sdjm 
5615e7798d9Sdjm void
tests(void)5625e7798d9Sdjm tests(void)
5635e7798d9Sdjm {
5645e7798d9Sdjm 	extern char *__progname;
5655e7798d9Sdjm 	LogLevel ll = test_is_verbose() ?
5665e7798d9Sdjm 	    SYSLOG_LEVEL_DEBUG3 : SYSLOG_LEVEL_QUIET;
5675e7798d9Sdjm 
5685e7798d9Sdjm 	/* test_cert_parse() are a bit spammy to error() by default... */
5695e7798d9Sdjm 	log_init(__progname, ll, SYSLOG_FACILITY_USER, 1);
5705e7798d9Sdjm 
5715e7798d9Sdjm 	test_authkeys_parse();
5725e7798d9Sdjm 	test_cert_parse();
5735e7798d9Sdjm 	test_merge();
5745e7798d9Sdjm }
575