1 /* $OpenBSD: asn1complex.c,v 1.4 2022/09/05 21:06:31 tb Exp $ */
2 /*
3 * Copyright (c) 2017, 2021 Joel Sing <jsing@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <openssl/asn1.h>
19 #include <openssl/asn1t.h>
20 #include <openssl/err.h>
21
22 #include <err.h>
23 #include <stdio.h>
24 #include <string.h>
25
26 static void
hexdump(const unsigned char * buf,size_t len)27 hexdump(const unsigned char *buf, size_t len)
28 {
29 size_t i;
30
31 for (i = 1; i <= len; i++)
32 fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n");
33
34 fprintf(stderr, "\n");
35 }
36
37 static int
asn1_compare_bytes(const char * label,const unsigned char * d1,int len1,const unsigned char * d2,int len2)38 asn1_compare_bytes(const char *label, const unsigned char *d1, int len1,
39 const unsigned char *d2, int len2)
40 {
41 if (len1 != len2) {
42 fprintf(stderr, "FAIL: %s - byte lengths differ "
43 "(%d != %d)\n", label, len1, len2);
44 return 0;
45 }
46 if (memcmp(d1, d2, len1) != 0) {
47 fprintf(stderr, "FAIL: %s - bytes differ\n", label);
48 fprintf(stderr, "Got:\n");
49 hexdump(d1, len1);
50 fprintf(stderr, "Want:\n");
51 hexdump(d2, len2);
52 return 0;
53 }
54 return 1;
55 }
56
57 /* Constructed octet string with length 12. */
58 const uint8_t asn1_constructed_basic_ber[] = {
59 0x24, 0x0c,
60 0x04, 0x01, 0x01,
61 0x04, 0x02, 0x01, 0x02,
62 0x04, 0x03, 0x01, 0x02, 0x03
63 };
64 const uint8_t asn1_constructed_basic_content[] = {
65 0x01, 0x01, 0x02, 0x01, 0x02, 0x03,
66 };
67
68 /* Nested constructed octet string. */
69 const uint8_t asn1_constructed_nested_ber[] = {
70 0x24, 0x1a,
71 0x04, 0x01, 0x01,
72 0x24, 0x15,
73 0x04, 0x02, 0x02, 0x03,
74 0x24, 0x0f,
75 0x24, 0x0d,
76 0x04, 0x03, 0x04, 0x05, 0x06,
77 0x24, 0x06,
78 0x24, 0x04,
79 0x04, 0x02, 0x07, 0x08,
80 };
81 const uint8_t asn1_constructed_nested_content[] = {
82 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
83 };
84
85 /* Deeply nested constructed octet string. */
86 const uint8_t asn1_constructed_deep_nested_ber[] = {
87 0x24, 0x1b,
88 0x04, 0x01, 0x01,
89 0x24, 0x16,
90 0x04, 0x02, 0x02, 0x03,
91 0x24, 0x10,
92 0x24, 0x0e,
93 0x04, 0x03, 0x04, 0x05, 0x06,
94 0x24, 0x07,
95 0x24, 0x05,
96 0x24, 0x03,
97 0x04, 0x01, 0x07,
98 };
99
100 /* Constructed octet string with indefinite length. */
101 const uint8_t asn1_constructed_indefinite_ber[] = {
102 0x24, 0x80,
103 0x04, 0x01, 0x01,
104 0x04, 0x02, 0x01, 0x02,
105 0x04, 0x03, 0x01, 0x02, 0x03,
106 0x00, 0x00,
107 };
108 const uint8_t asn1_constructed_indefinite_content[] = {
109 0x01, 0x01, 0x02, 0x01, 0x02, 0x03,
110 };
111
112 struct asn1_constructed_test {
113 const char *name;
114 const uint8_t *asn1;
115 size_t asn1_len;
116 const uint8_t *want;
117 size_t want_len;
118 int want_error;
119 int valid;
120 };
121
122 const struct asn1_constructed_test asn1_constructed_tests[] = {
123 {
124 .name = "basic constructed",
125 .asn1 = asn1_constructed_basic_ber,
126 .asn1_len = sizeof(asn1_constructed_basic_ber),
127 .want = asn1_constructed_basic_content,
128 .want_len = sizeof(asn1_constructed_basic_content),
129 .valid = 1,
130 },
131 {
132 .name = "nested constructed",
133 .asn1 = asn1_constructed_nested_ber,
134 .asn1_len = sizeof(asn1_constructed_nested_ber),
135 .want = asn1_constructed_nested_content,
136 .want_len = sizeof(asn1_constructed_nested_content),
137 .valid = 1,
138 },
139 {
140 .name = "deep nested constructed",
141 .asn1 = asn1_constructed_deep_nested_ber,
142 .asn1_len = sizeof(asn1_constructed_deep_nested_ber),
143 .want_error = ASN1_R_NESTED_ASN1_STRING,
144 .valid = 0,
145 },
146 {
147 .name = "indefinite length constructed",
148 .asn1 = asn1_constructed_indefinite_ber,
149 .asn1_len = sizeof(asn1_constructed_indefinite_ber),
150 .want = asn1_constructed_indefinite_content,
151 .want_len = sizeof(asn1_constructed_indefinite_content),
152 .valid = 1,
153 },
154 };
155
156 #define N_CONSTRUCTED_TESTS \
157 (sizeof(asn1_constructed_tests) / sizeof(*asn1_constructed_tests))
158
159 static int
do_asn1_constructed_test(const struct asn1_constructed_test * act)160 do_asn1_constructed_test(const struct asn1_constructed_test *act)
161 {
162 ASN1_OCTET_STRING *aos = NULL;
163 const uint8_t *p;
164 long err;
165 int failed = 1;
166
167 ERR_clear_error();
168
169 p = act->asn1;
170 aos = d2i_ASN1_OCTET_STRING(NULL, &p, act->asn1_len);
171 if (!act->valid) {
172 if (aos != NULL) {
173 fprintf(stderr, "FAIL: invalid ASN.1 decoded\n");
174 goto failed;
175 }
176 if (act->want_error != 0) {
177 err = ERR_peek_error();
178 if (ERR_GET_REASON(err) != act->want_error) {
179 fprintf(stderr, "FAIL: got error reason %d,"
180 "want %d", ERR_GET_REASON(err),
181 act->want_error);
182 goto failed;
183 }
184 }
185 goto done;
186 }
187 if (aos == NULL) {
188 fprintf(stderr, "FAIL: failed to decode ASN.1 constructed "
189 "octet string\n");
190 ERR_print_errors_fp(stderr);
191 goto failed;
192 }
193 if (!asn1_compare_bytes(act->name, ASN1_STRING_data(aos),
194 ASN1_STRING_length(aos), act->want, act->want_len))
195 goto failed;
196
197 done:
198 failed = 0;
199
200 failed:
201 ASN1_OCTET_STRING_free(aos);
202
203 return failed;
204 }
205
206 static int
do_asn1_constructed_tests(void)207 do_asn1_constructed_tests(void)
208 {
209 const struct asn1_constructed_test *act;
210 int failed = 0;
211 size_t i;
212
213 for (i = 0; i < N_CONSTRUCTED_TESTS; i++) {
214 act = &asn1_constructed_tests[i];
215 failed |= do_asn1_constructed_test(act);
216 }
217
218 return failed;
219 }
220
221 /* Sequence with length. */
222 const uint8_t asn1_sequence_ber[] = {
223 0x30, 0x16,
224 0x04, 0x01, 0x01,
225 0x04, 0x02, 0x01, 0x02,
226 0x04, 0x03, 0x01, 0x02, 0x03,
227 0x30, 0x80, 0x04, 0x01, 0x01, 0x00, 0x00,
228 0x04, 0x01, 0x01,
229
230 0x04, 0x01, 0x01, /* Trailing data. */
231 };
232
233 const uint8_t asn1_sequence_content[] = {
234 0x30, 0x16, 0x04, 0x01, 0x01, 0x04, 0x02, 0x01,
235 0x02, 0x04, 0x03, 0x01, 0x02, 0x03, 0x30, 0x80,
236 0x04, 0x01, 0x01, 0x00, 0x00, 0x04, 0x01, 0x01,
237 };
238
239 /* Sequence with indefinite length. */
240 const uint8_t asn1_sequence_indefinite_ber[] = {
241 0x30, 0x80,
242 0x04, 0x01, 0x01,
243 0x04, 0x02, 0x01, 0x02,
244 0x04, 0x03, 0x01, 0x02, 0x03,
245 0x30, 0x80, 0x04, 0x01, 0x01, 0x00, 0x00,
246 0x04, 0x01, 0x01,
247 0x00, 0x00,
248
249 0x04, 0x01, 0x01, /* Trailing data. */
250 };
251
252 const uint8_t asn1_sequence_indefinite_content[] = {
253 0x30, 0x80, 0x04, 0x01, 0x01, 0x04, 0x02, 0x01,
254 0x02, 0x04, 0x03, 0x01, 0x02, 0x03, 0x30, 0x80,
255 0x04, 0x01, 0x01, 0x00, 0x00, 0x04, 0x01, 0x01,
256 0x00, 0x00,
257 };
258
259 static int
do_asn1_sequence_string_tests(void)260 do_asn1_sequence_string_tests(void)
261 {
262 ASN1_STRING *astr = NULL;
263 const uint8_t *p;
264 long len;
265 int failed = 1;
266
267 ERR_clear_error();
268
269 /*
270 * Test decoding of sequence with length and indefinite length into
271 * a string - in this case the ASN.1 is not decoded and is stored
272 * directly as the content for the string.
273 */
274 if ((astr = ASN1_STRING_new()) == NULL) {
275 fprintf(stderr, "FAIL: ASN1_STRING_new() returned NULL\n");
276 goto failed;
277 }
278
279 p = asn1_sequence_ber;
280 len = sizeof(asn1_sequence_ber);
281 if (ASN1_item_d2i((ASN1_VALUE **)&astr, &p, len,
282 &ASN1_SEQUENCE_it) == NULL) {
283 fprintf(stderr, "FAIL: failed to decode ASN1_SEQUENCE\n");
284 ERR_print_errors_fp(stderr);
285 goto failed;
286 }
287
288 if (!asn1_compare_bytes("sequence", ASN1_STRING_data(astr),
289 ASN1_STRING_length(astr), asn1_sequence_content,
290 sizeof(asn1_sequence_content)))
291 goto failed;
292
293 p = asn1_sequence_indefinite_ber;
294 len = sizeof(asn1_sequence_indefinite_ber);
295 if (ASN1_item_d2i((ASN1_VALUE **)&astr, &p, len,
296 &ASN1_SEQUENCE_it) == NULL) {
297 fprintf(stderr, "FAIL: failed to decode ASN1_SEQUENCE\n");
298 ERR_print_errors_fp(stderr);
299 goto failed;
300 }
301
302 if (!asn1_compare_bytes("sequence indefinite", ASN1_STRING_data(astr),
303 ASN1_STRING_length(astr), asn1_sequence_indefinite_content,
304 sizeof(asn1_sequence_indefinite_content)))
305 goto failed;
306
307 failed = 0;
308
309 failed:
310 ASN1_STRING_free(astr);
311
312 return failed;
313 }
314
315 int
main(int argc,char ** argv)316 main(int argc, char **argv)
317 {
318 int failed = 0;
319
320 failed |= do_asn1_constructed_tests();
321 failed |= do_asn1_sequence_string_tests();
322
323 return (failed);
324 }
325