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