xref: /freebsd/crypto/openssh/regress/unittests/servconf/tests.c (revision bb5c77e9d281d6def6835d48249898764bc6a5fe)
1 /* 	$OpenBSD: tests.c,v 1.1 2026/05/31 11:39:44 djm Exp $ */
2 /*
3  * Regress tests for servconf.h server configuration API
4  *
5  * Placed in the public domain
6  */
7 
8 #include "includes.h"
9 
10 #include <sys/types.h>
11 #include <limits.h>
12 #include <stdio.h>
13 #include <stdint.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 #include "../test_helper/test_helper.h"
18 
19 #include "log.h"
20 #include "misc.h"
21 #include "servconf.h"
22 #include "sshbuf.h"
23 #include "ssherr.h"
24 #include "xmalloc.h"
25 
26 struct sshbuf *cfg;
27 
28 /* stub */
29 int auth2_methods_valid(const char *methods, int need_enable);
30 int
auth2_methods_valid(const char * methods,int need_enable)31 auth2_methods_valid(const char *methods, int need_enable)
32 {
33 	return 1;
34 }
35 
36 static void
onerror(void * fuzz)37 onerror(void *fuzz)
38 {
39 	fprintf(stderr, "Failed during fuzz:\n");
40 	fuzz_dump((struct fuzz *)fuzz);
41 }
42 
43 static void
set_string(char ** dst,const char * s)44 set_string(char **dst, const char *s)
45 {
46 	*dst = s == NULL ? NULL : xstrdup(s);
47 }
48 
49 static char **
new_string_array(u_int n)50 new_string_array(u_int n)
51 {
52 	return xcalloc(n, sizeof(char *));
53 }
54 
55 static void
set_test_options(ServerOptions * o)56 set_test_options(ServerOptions *o)
57 {
58 	initialize_server_options(o);
59 
60 	o->num_ports = 2;
61 	o->ports[0] = 22;
62 	o->ports[1] = 2022;
63 	o->ip_qos_interactive = 0x10;
64 	o->ip_qos_bulk = 0x08;
65 	o->log_facility = SYSLOG_FACILITY_AUTH;
66 	o->log_level = SYSLOG_LEVEL_DEBUG3;
67 	o->fwd_opts.gateway_ports = 1;
68 	o->fwd_opts.streamlocal_bind_mask = 0177;
69 	o->fwd_opts.streamlocal_bind_unlink = 1;
70 	o->permit_user_env = 1;
71 	set_string(&o->permit_user_env_allowlist, "");
72 	o->rekey_limit = 123456789;
73 	o->rekey_interval = 600;
74 	o->timing_secret = 0x0102030405060708ULL;
75 
76 	set_string(&o->routing_domain, "");
77 	set_string(&o->banner, NULL);
78 	set_string(&o->adm_forced_command, "internal-sftp");
79 	set_string(&o->chroot_directory, "");
80 	set_string(&o->host_key_agent, NULL);
81 	set_string(&o->authorized_keys_command, "/bin/echo");
82 	set_string(&o->authorized_keys_command_user, "");
83 	set_string(&o->authorized_principals_file, NULL);
84 
85 	o->num_authkeys_files = 3;
86 	o->authorized_keys_files = new_string_array(o->num_authkeys_files);
87 	set_string(&o->authorized_keys_files[0], NULL);
88 	set_string(&o->authorized_keys_files[1], "");
89 	set_string(&o->authorized_keys_files[2], ".ssh/authorized_keys");
90 
91 	o->num_log_verbose = 2;
92 	o->log_verbose = new_string_array(o->num_log_verbose);
93 	set_string(&o->log_verbose[0], NULL);
94 	set_string(&o->log_verbose[1], "kex.c:*");
95 
96 	o->num_host_key_files = 3;
97 	o->host_key_file_userprovided =
98 	    xcalloc(o->num_host_key_files,
99 	    sizeof(*o->host_key_file_userprovided));
100 	o->host_key_files = new_string_array(o->num_host_key_files);
101 	o->host_key_file_userprovided[0] = 0;
102 	o->host_key_file_userprovided[1] = 1;
103 	o->host_key_file_userprovided[2] = -1;
104 	set_string(&o->host_key_files[0], NULL);
105 	set_string(&o->host_key_files[1], "");
106 	set_string(&o->host_key_files[2], "/tmp/ssh_host_ed25519_key");
107 
108 	o->num_queued_listens = 2;
109 	o->queued_listen_addrs = xcalloc(o->num_queued_listens,
110 	    sizeof(*o->queued_listen_addrs));
111 	set_string(&o->queued_listen_addrs[0].addr, "127.0.0.1");
112 	o->queued_listen_addrs[0].port = 2222;
113 	set_string(&o->queued_listen_addrs[0].rdomain, NULL);
114 	set_string(&o->queued_listen_addrs[1].addr, "::1");
115 	o->queued_listen_addrs[1].port = -1;
116 	set_string(&o->queued_listen_addrs[1].rdomain, "");
117 
118 	o->num_subsystems = 2;
119 	o->subsystem_name = new_string_array(o->num_subsystems);
120 	o->subsystem_command = new_string_array(o->num_subsystems);
121 	o->subsystem_args = new_string_array(o->num_subsystems);
122 	set_string(&o->subsystem_name[0], "sftp");
123 	set_string(&o->subsystem_command[0], "internal-sftp");
124 	set_string(&o->subsystem_args[0], "internal-sftp -f AUTH");
125 	set_string(&o->subsystem_name[1], "echo");
126 	set_string(&o->subsystem_command[1], "/bin/echo");
127 	set_string(&o->subsystem_args[1], "/bin/echo hello");
128 }
129 
130 static void
check_roundtrip(const ServerOptions * o)131 check_roundtrip(const ServerOptions *o)
132 {
133 	struct sshbuf *buf = NULL;
134 	ServerOptions out;
135 
136 	initialize_server_options(&out);
137 	ASSERT_INT_EQ(serialise_server_options(o, &buf), 0);
138 	ASSERT_PTR_NE(buf, NULL);
139 	ASSERT_INT_EQ(deserialise_server_options(buf, &out), 0);
140 	ASSERT_SIZE_T_EQ(sshbuf_len(buf), 0);
141 
142 	ASSERT_U_INT_EQ(out.num_ports, 2);
143 	ASSERT_INT_EQ(out.ports[0], 22);
144 	ASSERT_INT_EQ(out.ports[1], 2022);
145 	ASSERT_INT_EQ(out.ip_qos_interactive, 0x10);
146 	ASSERT_INT_EQ(out.ip_qos_bulk, 0x08);
147 	ASSERT_INT_EQ(out.log_facility, SYSLOG_FACILITY_AUTH);
148 	ASSERT_INT_EQ(out.log_level, SYSLOG_LEVEL_DEBUG3);
149 	ASSERT_INT_EQ(out.fwd_opts.gateway_ports, 1);
150 	ASSERT_INT_EQ(out.fwd_opts.streamlocal_bind_mask, 0177);
151 	ASSERT_INT_EQ(out.fwd_opts.streamlocal_bind_unlink, 1);
152 	ASSERT_INT_EQ(out.permit_user_env, 1);
153 	ASSERT_STRING_EQ(out.permit_user_env_allowlist, "");
154 	ASSERT_LONG_LONG_EQ(out.rekey_limit, 123456789);
155 	ASSERT_INT_EQ(out.rekey_interval, 600);
156 	ASSERT_U64_EQ(out.timing_secret, 0x0102030405060708ULL);
157 
158 	ASSERT_STRING_EQ(out.routing_domain, "");
159 	ASSERT_PTR_EQ(out.banner, NULL);
160 	ASSERT_STRING_EQ(out.adm_forced_command, "internal-sftp");
161 	ASSERT_STRING_EQ(out.chroot_directory, "");
162 	ASSERT_PTR_EQ(out.host_key_agent, NULL);
163 	ASSERT_STRING_EQ(out.authorized_keys_command, "/bin/echo");
164 	ASSERT_STRING_EQ(out.authorized_keys_command_user, "");
165 	ASSERT_PTR_EQ(out.authorized_principals_file, NULL);
166 
167 	ASSERT_U_INT_EQ(out.num_authkeys_files, 3);
168 	ASSERT_PTR_EQ(out.authorized_keys_files[0], NULL);
169 	ASSERT_STRING_EQ(out.authorized_keys_files[1], "");
170 	ASSERT_STRING_EQ(out.authorized_keys_files[2], ".ssh/authorized_keys");
171 
172 	ASSERT_U_INT_EQ(out.num_log_verbose, 2);
173 	ASSERT_PTR_EQ(out.log_verbose[0], NULL);
174 	ASSERT_STRING_EQ(out.log_verbose[1], "kex.c:*");
175 
176 	ASSERT_U_INT_EQ(out.num_host_key_files, 3);
177 	ASSERT_INT_EQ(out.host_key_file_userprovided[0], 0);
178 	ASSERT_INT_EQ(out.host_key_file_userprovided[1], 1);
179 	ASSERT_INT_EQ(out.host_key_file_userprovided[2], -1);
180 	ASSERT_PTR_EQ(out.host_key_files[0], NULL);
181 	ASSERT_STRING_EQ(out.host_key_files[1], "");
182 	ASSERT_STRING_EQ(out.host_key_files[2], "/tmp/ssh_host_ed25519_key");
183 
184 	ASSERT_U_INT_EQ(out.num_queued_listens, 2);
185 	ASSERT_STRING_EQ(out.queued_listen_addrs[0].addr, "127.0.0.1");
186 	ASSERT_INT_EQ(out.queued_listen_addrs[0].port, 2222);
187 	ASSERT_PTR_EQ(out.queued_listen_addrs[0].rdomain, NULL);
188 	ASSERT_STRING_EQ(out.queued_listen_addrs[1].addr, "::1");
189 	ASSERT_INT_EQ(out.queued_listen_addrs[1].port, -1);
190 	ASSERT_STRING_EQ(out.queued_listen_addrs[1].rdomain, "");
191 
192 	ASSERT_U_INT_EQ(out.num_subsystems, 2);
193 	ASSERT_STRING_EQ(out.subsystem_name[0], "sftp");
194 	ASSERT_STRING_EQ(out.subsystem_command[0], "internal-sftp");
195 	ASSERT_STRING_EQ(out.subsystem_args[0], "internal-sftp -f AUTH");
196 	ASSERT_STRING_EQ(out.subsystem_name[1], "echo");
197 	ASSERT_STRING_EQ(out.subsystem_command[1], "/bin/echo");
198 	ASSERT_STRING_EQ(out.subsystem_args[1], "/bin/echo hello");
199 
200 	free_server_options(&out);
201 	sshbuf_free(buf);
202 }
203 
204 static void
check_rejects_trailing_data(const ServerOptions * o)205 check_rejects_trailing_data(const ServerOptions *o)
206 {
207 	struct sshbuf *buf = NULL;
208 	ServerOptions out;
209 	int r;
210 
211 	initialize_server_options(&out);
212 	ASSERT_INT_EQ(serialise_server_options(o, &buf), 0);
213 	ASSERT_PTR_NE(buf, NULL);
214 	ASSERT_INT_EQ(sshbuf_put_u8(buf, 0), 0);
215 	r = deserialise_server_options(buf, &out);
216 	ASSERT_INT_EQ(r, SSH_ERR_INVALID_FORMAT);
217 	free_server_options(&out);
218 	sshbuf_free(buf);
219 }
220 
221 static void
check_rejects_bad_version(const ServerOptions * o)222 check_rejects_bad_version(const ServerOptions *o)
223 {
224 	struct sshbuf *buf = NULL;
225 	ServerOptions out;
226 	int r;
227 
228 	initialize_server_options(&out);
229 	ASSERT_INT_EQ(serialise_server_options(o, &buf), 0);
230 	ASSERT_PTR_NE(buf, NULL);
231 	ASSERT_PTR_NE(sshbuf_mutable_ptr(buf), NULL);
232 	POKE_U32(sshbuf_mutable_ptr(buf), 2);
233 	r = deserialise_server_options(buf, &out);
234 	ASSERT_INT_EQ(r, SSH_ERR_INVALID_FORMAT);
235 	free_server_options(&out);
236 	sshbuf_free(buf);
237 }
238 
239 static void
check_rejects_bad_port_count(const ServerOptions * o)240 check_rejects_bad_port_count(const ServerOptions *o)
241 {
242 	struct sshbuf *buf = NULL;
243 	ServerOptions out;
244 	int r;
245 
246 	initialize_server_options(&out);
247 	ASSERT_INT_EQ(serialise_server_options(o, &buf), 0);
248 	ASSERT_PTR_NE(buf, NULL);
249 	ASSERT_SIZE_T_GT(sshbuf_len(buf), 8);
250 	ASSERT_PTR_NE(sshbuf_mutable_ptr(buf), NULL);
251 	POKE_U32(sshbuf_mutable_ptr(buf) + 4, MAX_PORTS + 1);
252 	r = deserialise_server_options(buf, &out);
253 	ASSERT_INT_EQ(r, SSH_ERR_INVALID_FORMAT);
254 	free_server_options(&out);
255 	sshbuf_free(buf);
256 }
257 
258 static void
check_roundtrip_signed_limits(const ServerOptions * o)259 check_roundtrip_signed_limits(const ServerOptions *o)
260 {
261 	struct sshbuf *buf = NULL;
262 	ServerOptions out, in;
263 
264 	initialize_server_options(&out);
265 	in = *o;
266 	in.fwd_opts.streamlocal_bind_mask = (mode_t)-1;
267 	in.ip_qos_bulk = INT_MIN;
268 	in.rekey_limit = INT64_MIN;
269 	ASSERT_INT_EQ(serialise_server_options(&in, &buf), 0);
270 	ASSERT_PTR_NE(buf, NULL);
271 	ASSERT_INT_EQ(deserialise_server_options(buf, &out), 0);
272 	ASSERT_INT_EQ(out.fwd_opts.streamlocal_bind_mask == (mode_t)-1, 1);
273 	ASSERT_INT_EQ(out.ip_qos_bulk, INT_MIN);
274 	ASSERT_LONG_LONG_EQ(out.rekey_limit, INT64_MIN);
275 	free_server_options(&out);
276 	sshbuf_free(buf);
277 }
278 
279 static void
attempt_deserialise_blob(const u_char * p,size_t len)280 attempt_deserialise_blob(const u_char *p, size_t len)
281 {
282 	struct sshbuf *buf;
283 	ServerOptions out;
284 
285 	initialize_server_options(&out);
286 	ASSERT_PTR_NE(buf = sshbuf_from(p, len), NULL);
287 	(void)deserialise_server_options(buf, &out);
288 	free_server_options(&out);
289 	sshbuf_free(buf);
290 }
291 
292 static void
check_fuzz_deserialise(const ServerOptions * o)293 check_fuzz_deserialise(const ServerOptions *o)
294 {
295 	struct sshbuf *buf = NULL;
296 	struct fuzz *fuzz;
297 	u_int fuzzers = FUZZ_1_BIT_FLIP | FUZZ_1_BYTE_FLIP |
298 	    FUZZ_TRUNCATE_START | FUZZ_TRUNCATE_END;
299 
300 	if (test_is_fast())
301 		fuzzers &= ~FUZZ_1_BIT_FLIP;
302 	if (test_is_slow())
303 		fuzzers |= FUZZ_2_BYTE_FLIP;
304 
305 	ASSERT_INT_EQ(serialise_server_options(o, &buf), 0);
306 	ASSERT_PTR_NE(buf, NULL);
307 	fuzz = fuzz_begin(fuzzers, sshbuf_ptr(buf), sshbuf_len(buf));
308 	TEST_ONERROR(onerror, fuzz);
309 	for (; !fuzz_done(fuzz); fuzz_next(fuzz))
310 		attempt_deserialise_blob(fuzz_ptr(fuzz), fuzz_len(fuzz));
311 	TEST_ONERROR(NULL, NULL);
312 	fuzz_cleanup(fuzz);
313 	sshbuf_free(buf);
314 }
315 
316 void
tests(void)317 tests(void)
318 {
319 	ServerOptions o;
320 
321 	log_init("test_servconf", SYSLOG_LEVEL_QUIET, SYSLOG_FACILITY_AUTH, 1);
322 
323 	TEST_START("server options round trip preserves nullable state");
324 	set_test_options(&o);
325 	check_roundtrip(&o);
326 	free_server_options(&o);
327 	TEST_DONE();
328 
329 	TEST_START("server options reject trailing data");
330 	set_test_options(&o);
331 	check_rejects_trailing_data(&o);
332 	free_server_options(&o);
333 	TEST_DONE();
334 
335 	TEST_START("server options reject unsupported version");
336 	set_test_options(&o);
337 	check_rejects_bad_version(&o);
338 	free_server_options(&o);
339 	TEST_DONE();
340 
341 	TEST_START("server options reject bad port count");
342 	set_test_options(&o);
343 	check_rejects_bad_port_count(&o);
344 	free_server_options(&o);
345 	TEST_DONE();
346 
347 	TEST_START("server options round trip signed limits");
348 	set_test_options(&o);
349 	check_roundtrip_signed_limits(&o);
350 	free_server_options(&o);
351 	TEST_DONE();
352 
353 	TEST_START("server options deserialise fuzz");
354 	set_test_options(&o);
355 	check_fuzz_deserialise(&o);
356 	free_server_options(&o);
357 	TEST_DONE();
358 }
359 
360 void
benchmarks(void)361 benchmarks(void)
362 {
363 	printf("no benchmarks\n");
364 }
365