]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
13471436 | 2 | |
dccca82b LP |
3 | #include <errno.h> |
4 | ||
13471436 RC |
5 | #include "alloc-util.h" |
6 | #include "hexdecoct.h" | |
7 | #include "macro.h" | |
82b4ec44 | 8 | #include "random-util.h" |
13471436 RC |
9 | #include "string-util.h" |
10 | ||
11 | static void test_hexchar(void) { | |
12 | assert_se(hexchar(0xa) == 'a'); | |
13 | assert_se(hexchar(0x0) == '0'); | |
14 | } | |
15 | ||
16 | static void test_unhexchar(void) { | |
17 | assert_se(unhexchar('a') == 0xA); | |
18 | assert_se(unhexchar('A') == 0xA); | |
19 | assert_se(unhexchar('0') == 0x0); | |
20 | } | |
21 | ||
22 | static void test_base32hexchar(void) { | |
23 | assert_se(base32hexchar(0) == '0'); | |
24 | assert_se(base32hexchar(9) == '9'); | |
25 | assert_se(base32hexchar(10) == 'A'); | |
26 | assert_se(base32hexchar(31) == 'V'); | |
27 | } | |
28 | ||
29 | static void test_unbase32hexchar(void) { | |
30 | assert_se(unbase32hexchar('0') == 0); | |
31 | assert_se(unbase32hexchar('9') == 9); | |
32 | assert_se(unbase32hexchar('A') == 10); | |
33 | assert_se(unbase32hexchar('V') == 31); | |
34 | assert_se(unbase32hexchar('=') == -EINVAL); | |
35 | } | |
36 | ||
37 | static void test_base64char(void) { | |
38 | assert_se(base64char(0) == 'A'); | |
39 | assert_se(base64char(26) == 'a'); | |
40 | assert_se(base64char(63) == '/'); | |
41 | } | |
42 | ||
43 | static void test_unbase64char(void) { | |
44 | assert_se(unbase64char('A') == 0); | |
45 | assert_se(unbase64char('Z') == 25); | |
46 | assert_se(unbase64char('a') == 26); | |
47 | assert_se(unbase64char('z') == 51); | |
48 | assert_se(unbase64char('0') == 52); | |
49 | assert_se(unbase64char('9') == 61); | |
50 | assert_se(unbase64char('+') == 62); | |
51 | assert_se(unbase64char('/') == 63); | |
52 | assert_se(unbase64char('=') == -EINVAL); | |
53 | } | |
54 | ||
55 | static void test_octchar(void) { | |
56 | assert_se(octchar(00) == '0'); | |
57 | assert_se(octchar(07) == '7'); | |
58 | } | |
59 | ||
60 | static void test_unoctchar(void) { | |
61 | assert_se(unoctchar('0') == 00); | |
62 | assert_se(unoctchar('7') == 07); | |
63 | } | |
64 | ||
65 | static void test_decchar(void) { | |
66 | assert_se(decchar(0) == '0'); | |
67 | assert_se(decchar(9) == '9'); | |
68 | } | |
69 | ||
70 | static void test_undecchar(void) { | |
71 | assert_se(undecchar('0') == 0); | |
72 | assert_se(undecchar('9') == 9); | |
73 | } | |
74 | ||
4937b81a YW |
75 | static void test_unhexmem_one(const char *s, size_t l, int retval) { |
76 | _cleanup_free_ char *hex = NULL; | |
13471436 RC |
77 | _cleanup_free_ void *mem = NULL; |
78 | size_t len; | |
79 | ||
4937b81a YW |
80 | assert_se(unhexmem(s, l, &mem, &len) == retval); |
81 | if (retval == 0) { | |
82 | char *answer; | |
83 | ||
f5fbe71d | 84 | if (l == SIZE_MAX) |
4937b81a YW |
85 | l = strlen(s); |
86 | ||
dcd6361e | 87 | assert_se(hex = hexmem(mem, len)); |
490c5a37 | 88 | answer = strndupa(strempty(s), l); |
4937b81a YW |
89 | assert_se(streq(delete_chars(answer, WHITESPACE), hex)); |
90 | } | |
91 | } | |
92 | ||
93 | static void test_unhexmem(void) { | |
94 | const char *hex = "efa2149213"; | |
95 | const char *hex_space = " e f a\n 2\r 14\n\r\t9\t2 \n1\r3 \r\r\t"; | |
96 | const char *hex_invalid = "efa214921o"; | |
13471436 | 97 | |
4937b81a YW |
98 | test_unhexmem_one(NULL, 0, 0); |
99 | test_unhexmem_one("", 0, 0); | |
f5fbe71d YW |
100 | test_unhexmem_one("", SIZE_MAX, 0); |
101 | test_unhexmem_one(" \n \t\r \t\t \n\n\n", SIZE_MAX, 0); | |
4937b81a YW |
102 | test_unhexmem_one(hex_invalid, strlen(hex_invalid), -EINVAL); |
103 | test_unhexmem_one(hex_invalid, (size_t) - 1, -EINVAL); | |
104 | test_unhexmem_one(hex, strlen(hex) - 1, -EPIPE); | |
105 | test_unhexmem_one(hex, strlen(hex), 0); | |
f5fbe71d | 106 | test_unhexmem_one(hex, SIZE_MAX, 0); |
4937b81a | 107 | test_unhexmem_one(hex_space, strlen(hex_space), 0); |
f5fbe71d | 108 | test_unhexmem_one(hex_space, SIZE_MAX, 0); |
13471436 RC |
109 | } |
110 | ||
111 | /* https://tools.ietf.org/html/rfc4648#section-10 */ | |
112 | static void test_base32hexmem(void) { | |
113 | char *b32; | |
114 | ||
fbd0b64f | 115 | b32 = base32hexmem("", STRLEN(""), true); |
13471436 RC |
116 | assert_se(b32); |
117 | assert_se(streq(b32, "")); | |
118 | free(b32); | |
119 | ||
fbd0b64f | 120 | b32 = base32hexmem("f", STRLEN("f"), true); |
13471436 RC |
121 | assert_se(b32); |
122 | assert_se(streq(b32, "CO======")); | |
123 | free(b32); | |
124 | ||
fbd0b64f | 125 | b32 = base32hexmem("fo", STRLEN("fo"), true); |
13471436 RC |
126 | assert_se(b32); |
127 | assert_se(streq(b32, "CPNG====")); | |
128 | free(b32); | |
129 | ||
fbd0b64f | 130 | b32 = base32hexmem("foo", STRLEN("foo"), true); |
13471436 RC |
131 | assert_se(b32); |
132 | assert_se(streq(b32, "CPNMU===")); | |
133 | free(b32); | |
134 | ||
fbd0b64f | 135 | b32 = base32hexmem("foob", STRLEN("foob"), true); |
13471436 RC |
136 | assert_se(b32); |
137 | assert_se(streq(b32, "CPNMUOG=")); | |
138 | free(b32); | |
139 | ||
fbd0b64f | 140 | b32 = base32hexmem("fooba", STRLEN("fooba"), true); |
13471436 RC |
141 | assert_se(b32); |
142 | assert_se(streq(b32, "CPNMUOJ1")); | |
143 | free(b32); | |
144 | ||
fbd0b64f | 145 | b32 = base32hexmem("foobar", STRLEN("foobar"), true); |
13471436 RC |
146 | assert_se(b32); |
147 | assert_se(streq(b32, "CPNMUOJ1E8======")); | |
148 | free(b32); | |
149 | ||
fbd0b64f | 150 | b32 = base32hexmem("", STRLEN(""), false); |
13471436 RC |
151 | assert_se(b32); |
152 | assert_se(streq(b32, "")); | |
153 | free(b32); | |
154 | ||
fbd0b64f | 155 | b32 = base32hexmem("f", STRLEN("f"), false); |
13471436 RC |
156 | assert_se(b32); |
157 | assert_se(streq(b32, "CO")); | |
158 | free(b32); | |
159 | ||
fbd0b64f | 160 | b32 = base32hexmem("fo", STRLEN("fo"), false); |
13471436 RC |
161 | assert_se(b32); |
162 | assert_se(streq(b32, "CPNG")); | |
163 | free(b32); | |
164 | ||
fbd0b64f | 165 | b32 = base32hexmem("foo", STRLEN("foo"), false); |
13471436 RC |
166 | assert_se(b32); |
167 | assert_se(streq(b32, "CPNMU")); | |
168 | free(b32); | |
169 | ||
fbd0b64f | 170 | b32 = base32hexmem("foob", STRLEN("foob"), false); |
13471436 RC |
171 | assert_se(b32); |
172 | assert_se(streq(b32, "CPNMUOG")); | |
173 | free(b32); | |
174 | ||
fbd0b64f | 175 | b32 = base32hexmem("fooba", STRLEN("fooba"), false); |
13471436 RC |
176 | assert_se(b32); |
177 | assert_se(streq(b32, "CPNMUOJ1")); | |
178 | free(b32); | |
179 | ||
fbd0b64f | 180 | b32 = base32hexmem("foobar", STRLEN("foobar"), false); |
13471436 RC |
181 | assert_se(b32); |
182 | assert_se(streq(b32, "CPNMUOJ1E8")); | |
183 | free(b32); | |
184 | } | |
185 | ||
2d2c21af YW |
186 | static void test_unbase32hexmem_one(const char *hex, bool padding, int retval, const char *ans) { |
187 | _cleanup_free_ void *mem = NULL; | |
13471436 RC |
188 | size_t len; |
189 | ||
f5fbe71d | 190 | assert_se(unbase32hexmem(hex, SIZE_MAX, padding, &mem, &len) == retval); |
2d2c21af YW |
191 | if (retval == 0) { |
192 | char *str; | |
193 | ||
194 | str = strndupa(mem, len); | |
195 | assert_se(streq(str, ans)); | |
196 | } | |
197 | } | |
198 | ||
199 | static void test_unbase32hexmem(void) { | |
200 | test_unbase32hexmem_one("", true, 0, ""); | |
201 | ||
202 | test_unbase32hexmem_one("CO======", true, 0, "f"); | |
203 | test_unbase32hexmem_one("CPNG====", true, 0, "fo"); | |
204 | test_unbase32hexmem_one("CPNMU===", true, 0, "foo"); | |
205 | test_unbase32hexmem_one("CPNMUOG=", true, 0, "foob"); | |
206 | test_unbase32hexmem_one("CPNMUOJ1", true, 0, "fooba"); | |
207 | test_unbase32hexmem_one("CPNMUOJ1E8======", true, 0, "foobar"); | |
208 | ||
209 | test_unbase32hexmem_one("A", true, -EINVAL, NULL); | |
210 | test_unbase32hexmem_one("A=======", true, -EINVAL, NULL); | |
211 | test_unbase32hexmem_one("AAA=====", true, -EINVAL, NULL); | |
212 | test_unbase32hexmem_one("AAAAAA==", true, -EINVAL, NULL); | |
213 | test_unbase32hexmem_one("AB======", true, -EINVAL, NULL); | |
214 | test_unbase32hexmem_one("AAAB====", true, -EINVAL, NULL); | |
215 | test_unbase32hexmem_one("AAAAB===", true, -EINVAL, NULL); | |
216 | test_unbase32hexmem_one("AAAAAAB=", true, -EINVAL, NULL); | |
217 | ||
218 | test_unbase32hexmem_one("XPNMUOJ1", true, -EINVAL, NULL); | |
219 | test_unbase32hexmem_one("CXNMUOJ1", true, -EINVAL, NULL); | |
220 | test_unbase32hexmem_one("CPXMUOJ1", true, -EINVAL, NULL); | |
221 | test_unbase32hexmem_one("CPNXUOJ1", true, -EINVAL, NULL); | |
222 | test_unbase32hexmem_one("CPNMXOJ1", true, -EINVAL, NULL); | |
223 | test_unbase32hexmem_one("CPNMUXJ1", true, -EINVAL, NULL); | |
224 | test_unbase32hexmem_one("CPNMUOX1", true, -EINVAL, NULL); | |
225 | test_unbase32hexmem_one("CPNMUOJX", true, -EINVAL, NULL); | |
226 | ||
227 | test_unbase32hexmem_one("", false, 0, ""); | |
228 | test_unbase32hexmem_one("CO", false, 0, "f"); | |
229 | test_unbase32hexmem_one("CPNG", false, 0, "fo"); | |
230 | test_unbase32hexmem_one("CPNMU", false, 0, "foo"); | |
231 | test_unbase32hexmem_one("CPNMUOG", false, 0, "foob"); | |
232 | test_unbase32hexmem_one("CPNMUOJ1", false, 0, "fooba"); | |
233 | test_unbase32hexmem_one("CPNMUOJ1E8", false, 0, "foobar"); | |
234 | test_unbase32hexmem_one("CPNMUOG=", false, -EINVAL, NULL); | |
235 | test_unbase32hexmem_one("CPNMUOJ1E8======", false, -EINVAL, NULL); | |
236 | ||
2d2c21af YW |
237 | test_unbase32hexmem_one("A", false, -EINVAL, NULL); |
238 | test_unbase32hexmem_one("AAA", false, -EINVAL, NULL); | |
239 | test_unbase32hexmem_one("AAAAAA", false, -EINVAL, NULL); | |
240 | test_unbase32hexmem_one("AB", false, -EINVAL, NULL); | |
241 | test_unbase32hexmem_one("AAAB", false, -EINVAL, NULL); | |
242 | test_unbase32hexmem_one("AAAAB", false, -EINVAL, NULL); | |
243 | test_unbase32hexmem_one("AAAAAAB", false, -EINVAL, NULL); | |
13471436 RC |
244 | } |
245 | ||
246 | /* https://tools.ietf.org/html/rfc4648#section-10 */ | |
247 | static void test_base64mem(void) { | |
248 | char *b64; | |
249 | ||
fbd0b64f | 250 | assert_se(base64mem("", STRLEN(""), &b64) == 0); |
13471436 RC |
251 | assert_se(streq(b64, "")); |
252 | free(b64); | |
253 | ||
fbd0b64f | 254 | assert_se(base64mem("f", STRLEN("f"), &b64) == 4); |
13471436 RC |
255 | assert_se(streq(b64, "Zg==")); |
256 | free(b64); | |
257 | ||
fbd0b64f | 258 | assert_se(base64mem("fo", STRLEN("fo"), &b64) == 4); |
13471436 RC |
259 | assert_se(streq(b64, "Zm8=")); |
260 | free(b64); | |
261 | ||
fbd0b64f | 262 | assert_se(base64mem("foo", STRLEN("foo"), &b64) == 4); |
13471436 RC |
263 | assert_se(streq(b64, "Zm9v")); |
264 | free(b64); | |
265 | ||
fbd0b64f | 266 | assert_se(base64mem("foob", STRLEN("foob"), &b64) == 8); |
13471436 RC |
267 | assert_se(streq(b64, "Zm9vYg==")); |
268 | free(b64); | |
269 | ||
fbd0b64f | 270 | assert_se(base64mem("fooba", STRLEN("fooba"), &b64) == 8); |
13471436 RC |
271 | assert_se(streq(b64, "Zm9vYmE=")); |
272 | free(b64); | |
273 | ||
fbd0b64f | 274 | assert_se(base64mem("foobar", STRLEN("foobar"), &b64) == 8); |
13471436 RC |
275 | assert_se(streq(b64, "Zm9vYmFy")); |
276 | free(b64); | |
277 | } | |
278 | ||
82b4ec44 LP |
279 | static void test_base64mem_linebreak(void) { |
280 | uint8_t data[4096]; | |
281 | ||
282 | for (size_t i = 0; i < 20; i++) { | |
283 | _cleanup_free_ char *encoded = NULL; | |
284 | _cleanup_free_ void *decoded = NULL; | |
285 | size_t decoded_size; | |
286 | uint64_t n, m; | |
287 | ssize_t l; | |
288 | ||
289 | /* Try a bunch of differently sized blobs */ | |
290 | n = random_u64_range(sizeof(data)); | |
291 | random_bytes(data, n); | |
292 | ||
293 | /* Break at various different columns */ | |
294 | m = 1 + random_u64_range(n + 5); | |
295 | ||
296 | l = base64mem_full(data, n, m, &encoded); | |
297 | assert_se(l >= 0); | |
298 | assert_se(encoded); | |
299 | assert_se((size_t) l == strlen(encoded)); | |
300 | ||
301 | assert_se(unbase64mem(encoded, SIZE_MAX, &decoded, &decoded_size) >= 0); | |
302 | assert_se(decoded_size == n); | |
303 | assert_se(memcmp(data, decoded, n) == 0); | |
304 | ||
305 | for (size_t j = 0; j < (size_t) l; j++) | |
306 | assert_se((encoded[j] == '\n') == (j % (m + 1) == m)); | |
307 | } | |
308 | } | |
309 | ||
081f36d8 LP |
310 | static void test_unbase64mem_one(const char *input, const char *output, int ret) { |
311 | _cleanup_free_ void *buffer = NULL; | |
312 | size_t size = 0; | |
13471436 | 313 | |
f5fbe71d | 314 | assert_se(unbase64mem(input, SIZE_MAX, &buffer, &size) == ret); |
13471436 | 315 | |
081f36d8 LP |
316 | if (ret >= 0) { |
317 | assert_se(size == strlen(output)); | |
318 | assert_se(memcmp(buffer, output, size) == 0); | |
319 | assert_se(((char*) buffer)[size] == 0); | |
320 | } | |
321 | } | |
13471436 | 322 | |
081f36d8 | 323 | static void test_unbase64mem(void) { |
13471436 | 324 | |
081f36d8 LP |
325 | test_unbase64mem_one("", "", 0); |
326 | test_unbase64mem_one("Zg==", "f", 0); | |
327 | test_unbase64mem_one("Zm8=", "fo", 0); | |
328 | test_unbase64mem_one("Zm9v", "foo", 0); | |
329 | test_unbase64mem_one("Zm9vYg==", "foob", 0); | |
330 | test_unbase64mem_one("Zm9vYmE=", "fooba", 0); | |
331 | test_unbase64mem_one("Zm9vYmFy", "foobar", 0); | |
332 | ||
333 | test_unbase64mem_one(" ", "", 0); | |
334 | test_unbase64mem_one(" \n\r ", "", 0); | |
335 | test_unbase64mem_one(" Zg\n== ", "f", 0); | |
336 | test_unbase64mem_one(" Zm 8=\r", "fo", 0); | |
337 | test_unbase64mem_one(" Zm9\n\r\r\nv ", "foo", 0); | |
338 | test_unbase64mem_one(" Z m9vYg==\n\r", "foob", 0); | |
339 | test_unbase64mem_one(" Zm 9vYmE= ", "fooba", 0); | |
340 | test_unbase64mem_one(" Z m9v YmFy ", "foobar", 0); | |
341 | ||
342 | test_unbase64mem_one("A", NULL, -EPIPE); | |
343 | test_unbase64mem_one("A====", NULL, -EINVAL); | |
344 | test_unbase64mem_one("AAB==", NULL, -EINVAL); | |
345 | test_unbase64mem_one(" A A A B = ", NULL, -EINVAL); | |
346 | test_unbase64mem_one(" Z m 8 = q u u x ", NULL, -ENAMETOOLONG); | |
13471436 RC |
347 | } |
348 | ||
349 | static void test_hexdump(void) { | |
350 | uint8_t data[146]; | |
351 | unsigned i; | |
352 | ||
353 | hexdump(stdout, NULL, 0); | |
354 | hexdump(stdout, "", 0); | |
355 | hexdump(stdout, "", 1); | |
356 | hexdump(stdout, "x", 1); | |
357 | hexdump(stdout, "x", 2); | |
358 | hexdump(stdout, "foobar", 7); | |
359 | hexdump(stdout, "f\nobar", 7); | |
360 | hexdump(stdout, "xxxxxxxxxxxxxxxxxxxxyz", 23); | |
361 | ||
362 | for (i = 0; i < ELEMENTSOF(data); i++) | |
363 | data[i] = i*2; | |
364 | ||
365 | hexdump(stdout, data, sizeof(data)); | |
366 | } | |
367 | ||
368 | int main(int argc, char *argv[]) { | |
369 | test_hexchar(); | |
370 | test_unhexchar(); | |
371 | test_base32hexchar(); | |
372 | test_unbase32hexchar(); | |
373 | test_base64char(); | |
374 | test_unbase64char(); | |
375 | test_octchar(); | |
376 | test_unoctchar(); | |
377 | test_decchar(); | |
378 | test_undecchar(); | |
379 | test_unhexmem(); | |
380 | test_base32hexmem(); | |
381 | test_unbase32hexmem(); | |
382 | test_base64mem(); | |
82b4ec44 | 383 | test_base64mem_linebreak(); |
13471436 RC |
384 | test_unbase64mem(); |
385 | test_hexdump(); | |
386 | ||
387 | return 0; | |
388 | } |