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