1 /* $OpenBSD: asn1oct.c,v 1.4 2023/05/13 07:17:32 tb Exp $ */
2
3 /*
4 * Copyright (c) 2023 Theo Buehler <tb@openbsd.org>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <assert.h>
20 #include <err.h>
21 #include <string.h>
22
23 #include <openssl/asn1.h>
24 #include <openssl/x509v3.h>
25
26 #define TESTBUFFER_SIZE 20
27
28 static const struct i2s_asn1_octet_string_test {
29 const char *desc;
30 const uint8_t buf[TESTBUFFER_SIZE];
31 long len;
32 const char *want;
33 } i2s_test[] = {
34 {
35 .desc = "Empty buffer gives empty string",
36 .buf = { 0x00, },
37 .len = 0,
38 .want = "",
39 },
40 {
41 .desc = "all hex digits",
42 .buf = { 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef, },
43 .len = 8,
44 .want = "01:23:45:67:89:AB:CD:EF",
45 },
46 {
47 .desc = "all hex digits, scrambled",
48 .buf = { 0x98, 0x24, 0xbf, 0x3a, 0xc7, 0xd6, 0x01, 0x5e, },
49 .len = 8,
50 .want = "98:24:BF:3A:C7:D6:01:5E",
51 },
52 {
53 .desc = "Embedded 0 byte",
54 .buf = { 0x7a, 0x00, 0xbb, },
55 .len = 3,
56 .want = "7A:00:BB",
57 },
58 {
59 .desc = "All zeroes",
60 .buf = { 0x00, 0x00, 0x00, 0x00, 0x00, },
61 .len = 4,
62 .want = "00:00:00:00",
63 },
64 {
65 .desc = "All bits set",
66 .buf = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, },
67 .len = 8,
68 .want = "FF:FF:FF:FF:FF:FF:FF:FF",
69 },
70 {
71 .desc = "negative length",
72 .buf = { 0x00, },
73 .len = -1,
74 },
75 };
76
77 #define N_I2S_TESTS (sizeof(i2s_test) / sizeof(i2s_test[0]))
78
79 static int
test_i2s_ASN1_OCTET_STRING(const struct i2s_asn1_octet_string_test * test)80 test_i2s_ASN1_OCTET_STRING(const struct i2s_asn1_octet_string_test *test)
81 {
82 ASN1_OCTET_STRING *aos = NULL;
83 int should_fail = test->want == NULL;
84 char *got = NULL;
85 int failed = 0;
86
87 if ((aos = ASN1_OCTET_STRING_new()) == NULL)
88 errx(1, "ASN1_OCTET_STRING_new");
89
90 if (!ASN1_STRING_set(aos, (void *)test->buf, test->len))
91 errx(1, "ASN1_STRING_set");
92
93 if ((got = i2s_ASN1_OCTET_STRING(NULL, aos)) == NULL) {
94 if (!should_fail)
95 errx(1, "i2s_ASN1_OCTET_STRING");
96 }
97
98 if (!should_fail && strcmp(test->want, got) != 0) {
99 fprintf(stderr, "%s: \"%s\" failed: want \"%s\", got \"%s\"\n",
100 __func__, test->desc, test->want, got);
101 failed |= 1;
102 }
103
104 ASN1_OCTET_STRING_free(aos);
105 free(got);
106
107 return failed;
108 }
109
110 static int
test_new_ASN1_OCTET_STRING(void)111 test_new_ASN1_OCTET_STRING(void)
112 {
113 ASN1_OCTET_STRING *aos = NULL;
114 char *got;
115 int failed = 0;
116
117 if ((aos = ASN1_OCTET_STRING_new()) == NULL)
118 errx(1, "%s: ASN1_OCTET_STRING_new", __func__);
119 if ((got = i2s_ASN1_OCTET_STRING(NULL, aos)) == NULL)
120 errx(1, "%s: i2s_ASN1_OCTET_STRING", __func__);
121
122 if (strcmp("", got) != 0) {
123 fprintf(stderr, "%s failed: want \"\", got \"%s\"\n",
124 __func__, got);
125 failed |= 1;
126 }
127
128 ASN1_OCTET_STRING_free(aos);
129 free(got);
130
131 return failed;
132 }
133
134 static int
run_i2s_ASN1_OCTET_STRING_tests(void)135 run_i2s_ASN1_OCTET_STRING_tests(void)
136 {
137 size_t i;
138 int failed = 0;
139
140 failed |= test_new_ASN1_OCTET_STRING();
141
142 for (i = 0; i < N_I2S_TESTS; i++)
143 failed |= test_i2s_ASN1_OCTET_STRING(&i2s_test[i]);
144
145 return failed;
146 }
147
148 static const struct s2i_asn1_octet_string_test {
149 const char *desc;
150 const char *in;
151 const char *want;
152 } s2i_test[] = {
153 /* Tests that should succeed. */
154 {
155 .desc = "empty string",
156 .in = "",
157 .want = "",
158 },
159 {
160 .desc = "only colons",
161 .in = ":::::::",
162 .want = "",
163 },
164 {
165 .desc = "a 0 octet",
166 .in = "00",
167 .want = "00",
168 },
169 {
170 .desc = "a 0 octet with stupid colons",
171 .in = ":::00:::::",
172 .want = "00",
173 },
174 {
175 .desc = "more stupid colons",
176 .in = ":::C0fF::Ee:::::",
177 .want = "C0:FF:EE",
178 },
179 {
180 .desc = "all hex digits",
181 .in = "0123456789abcdef",
182 .want = "01:23:45:67:89:AB:CD:EF",
183 },
184
185 /* Tests that should fail. */
186 {
187 .desc = "colons between hex digits",
188 .in = "A:F",
189 },
190 {
191 .desc = "more colons between hex digits",
192 .in = "5:7",
193 },
194 {
195 .desc = "one hex digit",
196 .in = "1",
197 },
198 {
199 .desc = "three hex digits",
200 .in = "bad",
201 },
202 {
203 .desc = "three hex digits, colon after first digit",
204 .in = "b:ad",
205 },
206 {
207 .desc = "three hex digits, colon after second digit",
208 .in = "ba:d",
209 },
210 {
211 .desc = "non-hex digit",
212 .in = "g00d",
213 },
214 {
215 .desc = "non-hex digits",
216 .in = "d0gged",
217 },
218 {
219 .desc = "trailing non-hex digit",
220 .in = "d00der",
221 },
222 };
223
224 #define N_S2I_TESTS (sizeof(s2i_test) / sizeof(s2i_test[0]))
225
226 static int
test_s2i_ASN1_OCTET_STRING(const struct s2i_asn1_octet_string_test * test)227 test_s2i_ASN1_OCTET_STRING(const struct s2i_asn1_octet_string_test *test)
228 {
229 ASN1_OCTET_STRING *aos = NULL;
230 char *got = NULL;
231 int should_fail = test->want == NULL;
232 int failed = 0;
233
234 if ((aos = s2i_ASN1_OCTET_STRING(NULL, NULL, test->in)) == NULL) {
235 if (!should_fail)
236 errx(1, "%s: s2i_ASN1_OCTET_STRING", test->desc);
237 goto done;
238 }
239
240 if ((got = i2s_ASN1_OCTET_STRING(NULL, aos)) == NULL)
241 errx(1, "%s: i2s_ASN1_OCTET_STRING", test->desc);
242
243 assert(test->want != NULL);
244 if (strcmp(test->want, got) != 0) {
245 fprintf(stderr, "%s: \"%s\" failed: want \"%s\", got \"%s\"\n",
246 __func__, test->desc, test->want, got);
247 failed |= 1;
248 }
249
250 done:
251 ASN1_OCTET_STRING_free(aos);
252 free(got);
253
254 return failed;
255 }
256
257 static int
run_s2i_ASN1_OCTET_STRING_tests(void)258 run_s2i_ASN1_OCTET_STRING_tests(void)
259 {
260 size_t i;
261 int failed = 0;
262
263 failed |= test_new_ASN1_OCTET_STRING();
264
265 for (i = 0; i < N_S2I_TESTS; i++)
266 failed |= test_s2i_ASN1_OCTET_STRING(&s2i_test[i]);
267
268 return failed;
269 }
270
271 int
main(void)272 main(void)
273 {
274 int failed = 0;
275
276 failed |= run_i2s_ASN1_OCTET_STRING_tests();
277 failed |= run_s2i_ASN1_OCTET_STRING_tests();
278
279 return failed;
280 }
281