xref: /freebsd/crypto/openssh/regress/unittests/sshbuf/test_sshbuf.c (revision 2574974648c68c738aec3ff96644d888d7913a37)
1 /* 	$OpenBSD: test_sshbuf.c,v 1.3 2025/12/30 00:12:58 djm Exp $ */
2 /*
3  * Regress test for sshbuf.h buffer API
4  *
5  * Placed in the public domain
6  */
7 
8 #define SSHBUF_INTERNAL 1	/* access internals for testing */
9 #include "includes.h"
10 
11 #include <sys/types.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 "ssherr.h"
20 #include "sshbuf.h"
21 
22 void sshbuf_tests(void);
23 
24 #ifndef roundup
25 #define roundup(x, y)   ((((x)+((y)-1))/(y))*(y))
26 #endif
27 
28 void
sshbuf_tests(void)29 sshbuf_tests(void)
30 {
31 	struct sshbuf *p1, *p2, *p3;
32 	u_int v32;
33 	const u_char *cdp;
34 	u_char *dp;
35 	size_t sz;
36 	int r;
37 
38 	TEST_START("allocate sshbuf");
39 	p1 = sshbuf_new();
40 	ASSERT_PTR_NE(p1, NULL);
41 	TEST_DONE();
42 
43 	TEST_START("max size on fresh buffer");
44 	ASSERT_SIZE_T_GT(sshbuf_max_size(p1), 0);
45 	TEST_DONE();
46 
47 	TEST_START("available on fresh buffer");
48 	ASSERT_SIZE_T_GT(sshbuf_avail(p1), 0);
49 	TEST_DONE();
50 
51 	TEST_START("len = 0 on empty buffer");
52 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
53 	TEST_DONE();
54 
55 	TEST_START("set valid max size");
56 	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 65536), 0);
57 	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 65536);
58 	TEST_DONE();
59 
60 	TEST_START("available on limited buffer");
61 	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 65536);
62 	TEST_DONE();
63 
64 	TEST_START("free");
65 	sshbuf_free(p1);
66 	TEST_DONE();
67 
68 	TEST_START("consume on empty buffer");
69 	p1 = sshbuf_new();
70 	ASSERT_PTR_NE(p1, NULL);
71 	ASSERT_INT_EQ(sshbuf_consume(p1, 0), 0);
72 	ASSERT_INT_EQ(sshbuf_consume(p1, 1), SSH_ERR_MESSAGE_INCOMPLETE);
73 	sshbuf_free(p1);
74 	TEST_DONE();
75 
76 	TEST_START("consume_end on empty buffer");
77 	p1 = sshbuf_new();
78 	ASSERT_PTR_NE(p1, NULL);
79 	ASSERT_INT_EQ(sshbuf_consume_end(p1, 0), 0);
80 	ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), SSH_ERR_MESSAGE_INCOMPLETE);
81 	sshbuf_free(p1);
82 	TEST_DONE();
83 
84 	TEST_START("reserve space");
85 	p1 = sshbuf_new();
86 	ASSERT_PTR_NE(p1, NULL);
87 	r = sshbuf_reserve(p1, 1, &dp);
88 	ASSERT_INT_EQ(r, 0);
89 	ASSERT_PTR_NE(dp, NULL);
90 	*dp = 0x11;
91 	r = sshbuf_reserve(p1, 3, &dp);
92 	ASSERT_INT_EQ(r, 0);
93 	ASSERT_PTR_NE(dp, NULL);
94 	*dp++ = 0x22;
95 	*dp++ = 0x33;
96 	*dp++ = 0x44;
97 	TEST_DONE();
98 
99 	TEST_START("sshbuf_len on filled buffer");
100 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
101 	TEST_DONE();
102 
103 	TEST_START("sshbuf_ptr on filled buffer");
104 	cdp = sshbuf_ptr(p1);
105 	ASSERT_PTR_NE(cdp, NULL);
106 	ASSERT_U8_EQ(cdp[0], 0x11);
107 	ASSERT_U8_EQ(cdp[1], 0x22);
108 	ASSERT_U8_EQ(cdp[2], 0x33);
109 	ASSERT_U8_EQ(cdp[3], 0x44);
110 	TEST_DONE();
111 
112 	TEST_START("consume on filled buffer");
113 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
114 	ASSERT_INT_EQ(sshbuf_consume(p1, 0), 0);
115 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
116 	r = sshbuf_consume(p1, 64);
117 	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
118 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
119 	ASSERT_INT_EQ(sshbuf_consume(p1, 1), 0);
120 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 3);
121 	cdp = sshbuf_ptr(p1);
122 	ASSERT_PTR_NE(p1, NULL);
123 	ASSERT_U8_EQ(cdp[0], 0x22);
124 	ASSERT_INT_EQ(sshbuf_consume(p1, 2), 0);
125 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
126 	cdp = sshbuf_ptr(p1);
127 	ASSERT_PTR_NE(p1, NULL);
128 	ASSERT_U8_EQ(cdp[0], 0x44);
129 	r = sshbuf_consume(p1, 2);
130 	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
131 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
132 	ASSERT_INT_EQ(sshbuf_consume(p1, 1), 0);
133 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
134 	r = sshbuf_consume(p1, 1);
135 	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
136 	sshbuf_free(p1);
137 	TEST_DONE();
138 
139 	TEST_START("consume_end on filled buffer");
140 	p1 = sshbuf_new();
141 	ASSERT_PTR_NE(p1, NULL);
142 	r = sshbuf_reserve(p1, 4, &dp);
143 	ASSERT_INT_EQ(r, 0);
144 	ASSERT_PTR_NE(dp, NULL);
145 	*dp++ = 0x11;
146 	*dp++ = 0x22;
147 	*dp++ = 0x33;
148 	*dp++ = 0x44;
149 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
150 	r = sshbuf_consume_end(p1, 5);
151 	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
152 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 4);
153 	ASSERT_INT_EQ(sshbuf_consume_end(p1, 3), 0);
154 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1);
155 	cdp = sshbuf_ptr(p1);
156 	ASSERT_PTR_NE(cdp, NULL);
157 	ASSERT_U8_EQ(*cdp, 0x11);
158 	r = sshbuf_consume_end(p1, 2);
159 	ASSERT_INT_EQ(r, SSH_ERR_MESSAGE_INCOMPLETE);
160 	ASSERT_INT_EQ(sshbuf_consume_end(p1, 1), 0);
161 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
162 	sshbuf_free(p1);
163 	TEST_DONE();
164 
165 	TEST_START("fill limited buffer");
166 	p1 = sshbuf_new();
167 	ASSERT_PTR_NE(p1, NULL);
168 	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1223), 0);
169 	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
170 	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 1223);
171 	r = sshbuf_reserve(p1, 1223, &dp);
172 	ASSERT_INT_EQ(r, 0);
173 	ASSERT_PTR_NE(dp, NULL);
174 	memset(dp, 0xd7, 1223);
175 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1223);
176 	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 0);
177 	r = sshbuf_reserve(p1, 1, &dp);
178 	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
179 	ASSERT_PTR_EQ(dp, NULL);
180 	TEST_DONE();
181 
182 	TEST_START("consume and force compaction");
183 	ASSERT_INT_EQ(sshbuf_consume(p1, 223), 0);
184 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1000);
185 	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 223);
186 	r = sshbuf_reserve(p1, 224, &dp);
187 	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
188 	ASSERT_PTR_EQ(dp, NULL);
189 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1000);
190 	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 223);
191 	r = sshbuf_reserve(p1, 223, &dp);
192 	ASSERT_INT_EQ(r, 0);
193 	ASSERT_PTR_NE(dp, NULL);
194 	memset(dp, 0x7d, 223);
195 	cdp = sshbuf_ptr(p1);
196 	ASSERT_PTR_NE(cdp, NULL);
197 	ASSERT_MEM_FILLED_EQ(cdp, 0xd7, 1000);
198 	ASSERT_MEM_FILLED_EQ(cdp + 1000, 0x7d, 223);
199 	TEST_DONE();
200 
201 	TEST_START("resize full buffer");
202 	r = sshbuf_set_max_size(p1, 1000);
203 	ASSERT_INT_EQ(r, SSH_ERR_NO_BUFFER_SPACE);
204 	sz = roundup(1223 + SSHBUF_SIZE_INC * 3, SSHBUF_SIZE_INC);
205 	ASSERT_INT_EQ(sshbuf_set_max_size(p1, sz), 0);
206 	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), sz);
207 	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), sz - 1223);
208 	ASSERT_INT_EQ(sshbuf_len(p1), 1223);
209 	TEST_DONE();
210 
211 	/* NB. uses sshbuf internals */
212 	TEST_START("alloc chunking");
213 	r = sshbuf_reserve(p1, 1, &dp);
214 	ASSERT_INT_EQ(r, 0);
215 	ASSERT_PTR_NE(dp, NULL);
216 	*dp = 0xff;
217 	cdp = sshbuf_ptr(p1);
218 	ASSERT_PTR_NE(cdp, NULL);
219 	ASSERT_MEM_FILLED_EQ(cdp, 0xd7, 1000);
220 	ASSERT_MEM_FILLED_EQ(cdp + 1000, 0x7d, 223);
221 	ASSERT_MEM_FILLED_EQ(cdp + 1223, 0xff, 1);
222 	ASSERT_SIZE_T_EQ(sshbuf_alloc(p1) % SSHBUF_SIZE_INC, 0);
223 	sshbuf_free(p1);
224 	TEST_DONE();
225 
226 	TEST_START("reset buffer");
227 	p1 = sshbuf_new();
228 	ASSERT_PTR_NE(p1, NULL);
229 	ASSERT_INT_EQ(sshbuf_set_max_size(p1, 1223), 0);
230 	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
231 	r = sshbuf_reserve(p1, 1223, &dp);
232 	ASSERT_INT_EQ(r, 0);
233 	ASSERT_PTR_NE(dp, NULL);
234 	memset(dp, 0xd7, 1223);
235 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 1223);
236 	sshbuf_reset(p1);
237 	ASSERT_SIZE_T_EQ(sshbuf_max_size(p1), 1223);
238 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 0);
239 	ASSERT_SIZE_T_EQ(sshbuf_avail(p1), 1223);
240 	sshbuf_free(p1);
241 	TEST_DONE();
242 
243 	TEST_START("sshbuf_consume_upto_child");
244 	p1 = sshbuf_new();
245 	ASSERT_PTR_NE(p1, NULL);
246 	p2 = sshbuf_new();
247 	ASSERT_PTR_NE(p2, NULL);
248 	/* Unrelated buffers */
249 	ASSERT_INT_EQ(sshbuf_consume_upto_child(p1, p2),
250 	    SSH_ERR_INVALID_ARGUMENT);
251 	/* Simple success case */
252 	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0xdeadbeef), 0);
253 	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0x01020304), 0);
254 	ASSERT_INT_EQ(sshbuf_put_u32(p1, 0xfeedface), 0);
255 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), 12);
256 	p3 = sshbuf_fromb(p1);
257 	ASSERT_PTR_NE(p3, NULL);
258 	ASSERT_INT_EQ(sshbuf_get_u32(p3, &v32), 0);
259 	ASSERT_U32_EQ(v32, 0xdeadbeef);
260 	ASSERT_SIZE_T_EQ(sshbuf_len(p3), 8);
261 	ASSERT_INT_EQ(sshbuf_consume_upto_child(p1, p3), 0);
262 	ASSERT_SIZE_T_EQ(sshbuf_len(p1), sshbuf_len(p3));
263 	ASSERT_PTR_EQ(sshbuf_ptr(p1), sshbuf_ptr(p3));
264 	sshbuf_free(p3);
265 	/* Parent already consumed past child */
266 	p3 = sshbuf_fromb(p1);
267 	ASSERT_PTR_NE(p3, NULL);
268 	ASSERT_INT_EQ(sshbuf_get_u32(p1, &v32), 0);
269 	ASSERT_U32_EQ(v32, 0x01020304);
270 	ASSERT_INT_EQ(sshbuf_consume_upto_child(p1, p3),
271 	    SSH_ERR_INVALID_ARGUMENT);
272 	sshbuf_free(p1);
273 	sshbuf_free(p2);
274 	sshbuf_free(p3);
275 	TEST_DONE();
276 }
277