xref: /openbsd-src/regress/lib/libcrypto/asn1/asn1api.c (revision 7ae33d3d4cbc25b8e6a3bee8b4ea24ab0b62c83f)
1 /* $OpenBSD: asn1api.c,v 1.3 2022/07/09 14:47:42 tb Exp $ */
2 /*
3  * Copyright (c) 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/err.h>
20 
21 #include <err.h>
22 #include <stdio.h>
23 #include <string.h>
24 
25 const long asn1_tag2bits[] = {
26 	[0] = 0,
27 	[1] = 0,
28 	[2] = 0,
29 	[3] = B_ASN1_BIT_STRING,
30 	[4] = B_ASN1_OCTET_STRING,
31 	[5] = 0,
32 	[6] = 0,
33 	[7] = B_ASN1_UNKNOWN,
34 	[8] = B_ASN1_UNKNOWN,
35 	[9] = B_ASN1_UNKNOWN,
36 	[10] = B_ASN1_UNKNOWN,
37 	[11] = B_ASN1_UNKNOWN,
38 	[12] = B_ASN1_UTF8STRING,
39 	[13] = B_ASN1_UNKNOWN,
40 	[14] = B_ASN1_UNKNOWN,
41 	[15] = B_ASN1_UNKNOWN,
42 	[16] = B_ASN1_SEQUENCE,
43 	[17] = 0,
44 	[18] = B_ASN1_NUMERICSTRING,
45 	[19] = B_ASN1_PRINTABLESTRING,
46 	[20] = B_ASN1_T61STRING,
47 	[21] = B_ASN1_VIDEOTEXSTRING,
48 	[22] = B_ASN1_IA5STRING,
49 	[23] = B_ASN1_UTCTIME,
50 	[24] = B_ASN1_GENERALIZEDTIME,
51 	[25] = B_ASN1_GRAPHICSTRING,
52 	[26] = B_ASN1_ISO64STRING,
53 	[27] = B_ASN1_GENERALSTRING,
54 	[28] = B_ASN1_UNIVERSALSTRING,
55 	[29] = B_ASN1_UNKNOWN,
56 	[30] = B_ASN1_BMPSTRING,
57 };
58 
59 static int
asn1_tag2bit(void)60 asn1_tag2bit(void)
61 {
62 	int failed = 1;
63 	long bit;
64 	int i;
65 
66 	for (i = -3; i <= V_ASN1_NEG + 30; i++) {
67 		bit = ASN1_tag2bit(i);
68 		if (i >= 0 && i <= 30) {
69 			if (bit != asn1_tag2bits[i]) {
70 				fprintf(stderr, "FAIL: ASN1_tag2bit(%d) = 0x%lx,"
71 				    " want 0x%lx\n", i, bit, asn1_tag2bits[i]);
72 				goto failed;
73 			}
74 		} else {
75 			if (bit != 0) {
76 				fprintf(stderr, "FAIL: ASN1_tag2bit(%d) = 0x%lx,"
77 				    " want 0x0\n", i, bit);
78 				goto failed;
79 			}
80 		}
81 	}
82 
83 	failed = 0;
84 
85  failed:
86 	return failed;
87 }
88 
89 static int
asn1_tag2str(void)90 asn1_tag2str(void)
91 {
92 	int failed = 1;
93 	const char *s;
94 	int i;
95 
96 	for (i = -3; i <= V_ASN1_NEG + 30; i++) {
97 		if ((s = ASN1_tag2str(i)) == NULL) {
98 			fprintf(stderr, "FAIL: ASN1_tag2str(%d) returned "
99 			    "NULL\n", i);
100 			goto failed;
101 		}
102 		if ((i >= 0 && i <= 30) || i == V_ASN1_NEG_INTEGER ||
103 		    i == V_ASN1_NEG_ENUMERATED) {
104 			if (strcmp(s, "(unknown)") == 0) {
105 				fprintf(stderr, "FAIL: ASN1_tag2str(%d) = '%s',"
106 				    " want tag name\n", i, s);
107 				goto failed;
108 			}
109 		} else {
110 			if (strcmp(s, "(unknown)") != 0) {
111 				fprintf(stderr, "FAIL: ASN1_tag2str(%d) = '%s',"
112 				    " want '(unknown')\n", i, s);
113 				goto failed;
114 			}
115 		}
116 	}
117 
118 	failed = 0;
119 
120  failed:
121 	return failed;
122 }
123 
124 struct asn1_get_object_test {
125 	const uint8_t asn1[64];
126 	size_t asn1_len;
127 	size_t asn1_hdr_len;
128 	int want_ret;
129 	long want_length;
130 	int want_tag;
131 	int want_class;
132 	int want_error;
133 };
134 
135 const struct asn1_get_object_test asn1_get_object_tests[] = {
136 	{
137 		/* Zero tag and zero length (EOC). */
138 		.asn1 = {0x00, 0x00},
139 		.asn1_len = 2,
140 		.asn1_hdr_len = 2,
141 		.want_ret = 0x00,
142 		.want_length = 0,
143 		.want_tag = 0,
144 		.want_class = 0,
145 	},
146 	{
147 		/* Boolean with short form length. */
148 		.asn1 = {0x01, 0x01},
149 		.asn1_len = 3,
150 		.asn1_hdr_len = 2,
151 		.want_ret = 0x00,
152 		.want_length = 1,
153 		.want_tag = 1,
154 		.want_class = 0,
155 	},
156 	{
157 		/* Long form tag. */
158 		.asn1 = {0x1f, 0x7f, 0x01},
159 		.asn1_len = 3 + 128,
160 		.asn1_hdr_len = 3,
161 		.want_ret = 0x00,
162 		.want_length = 1,
163 		.want_tag = 127,
164 		.want_class = 0,
165 	},
166 	{
167 		/* Long form tag with class application. */
168 		.asn1 = {0x5f, 0x7f, 0x01},
169 		.asn1_len = 3 + 128,
170 		.asn1_hdr_len = 3,
171 		.want_ret = 0x00,
172 		.want_length = 1,
173 		.want_tag = 127,
174 		.want_class = 1 << 6,
175 	},
176 	{
177 		/* Long form tag with class context-specific. */
178 		.asn1 = {0x9f, 0x7f, 0x01},
179 		.asn1_len = 3 + 128,
180 		.asn1_hdr_len = 3,
181 		.want_ret = 0x00,
182 		.want_length = 1,
183 		.want_tag = 127,
184 		.want_class = 2 << 6,
185 	},
186 	{
187 		/* Long form tag with class private. */
188 		.asn1 = {0xdf, 0x7f, 0x01},
189 		.asn1_len = 3 + 128,
190 		.asn1_hdr_len = 3,
191 		.want_ret = 0x00,
192 		.want_length = 1,
193 		.want_tag = 127,
194 		.want_class = 3 << 6,
195 	},
196 	{
197 		/* Long form tag (maximum). */
198 		.asn1 = {0x1f, 0x87, 0xff, 0xff, 0xff, 0x7f, 0x01},
199 		.asn1_len = 8,
200 		.asn1_hdr_len = 7,
201 		.want_ret = 0x00,
202 		.want_length = 1,
203 		.want_tag = 0x7fffffff,
204 		.want_class = 0,
205 	},
206 	{
207 		/* Long form tag (maximum + 1). */
208 		.asn1 = {0x1f, 0x88, 0x80, 0x80, 0x80, 0x00, 0x01},
209 		.asn1_len = 8,
210 		.asn1_hdr_len = 7,
211 		.want_ret = 0x80,
212 		.want_error = ASN1_R_HEADER_TOO_LONG,
213 	},
214 	{
215 		/* OctetString with long form length. */
216 		.asn1 = {0x04, 0x81, 0x80},
217 		.asn1_len = 3 + 128,
218 		.asn1_hdr_len = 3,
219 		.want_ret = 0x00,
220 		.want_length = 128,
221 		.want_tag = 4,
222 		.want_class = 0,
223 	},
224 	{
225 		/* OctetString with long form length. */
226 		.asn1 = {0x04, 0x84, 0x7f, 0xff, 0xff, 0xf9},
227 		.asn1_len = 0x7fffffff,
228 		.asn1_hdr_len = 6,
229 		.want_ret = 0x00,
230 		.want_length = 0x7ffffff9,
231 		.want_tag = 4,
232 		.want_class = 0,
233 	},
234 	{
235 		/* Long form tag and long form length. */
236 		.asn1 = {0x1f, 0x87, 0xff, 0xff, 0xff, 0x7f, 0x84, 0x7f, 0xff, 0xff, 0xf4},
237 		.asn1_len = 0x7fffffff,
238 		.asn1_hdr_len = 11,
239 		.want_ret = 0x00,
240 		.want_length = 0x7ffffff4,
241 		.want_tag = 0x7fffffff,
242 		.want_class = 0,
243 	},
244 	{
245 		/* Constructed OctetString with definite length. */
246 		.asn1 = {0x24, 0x03},
247 		.asn1_len = 5,
248 		.asn1_hdr_len = 2,
249 		.want_ret = 0x20,
250 		.want_length = 3,
251 		.want_tag = 4,
252 		.want_class = 0,
253 	},
254 	{
255 		/* Constructed OctetString with indefinite length. */
256 		.asn1 = {0x24, 0x80},
257 		.asn1_len = 5,
258 		.asn1_hdr_len = 2,
259 		.want_ret = 0x21,
260 		.want_length = 0,
261 		.want_tag = 4,
262 		.want_class = 0,
263 	},
264 	{
265 		/* Boolean with indefinite length (invalid). */
266 		.asn1 = {0x01, 0x80},
267 		.asn1_len = 3,
268 		.want_ret = 0x80,
269 		.want_error = ASN1_R_HEADER_TOO_LONG,
270 	},
271 	{
272 		/* OctetString with insufficient data (only tag). */
273 		.asn1 = {0x04, 0x04},
274 		.asn1_len = 1,
275 		.want_ret = 0x80,
276 		.want_error = ASN1_R_HEADER_TOO_LONG,
277 	},
278 	{
279 		/* OctetString with insufficient data (missing content). */
280 		.asn1 = {0x04, 0x04},
281 		.asn1_len = 2,
282 		.asn1_hdr_len = 2,
283 		.want_ret = 0x80,
284 		.want_length = 4,
285 		.want_tag = 4,
286 		.want_class = 0,
287 		.want_error = ASN1_R_TOO_LONG,
288 	},
289 	{
290 		/* OctetString with insufficient data (partial content). */
291 		.asn1 = {0x04, 0x04},
292 		.asn1_len = 5,
293 		.asn1_hdr_len = 2,
294 		.want_ret = 0x80,
295 		.want_length = 4,
296 		.want_tag = 4,
297 		.want_class = 0,
298 		.want_error = ASN1_R_TOO_LONG,
299 	},
300 	{
301 		/* Constructed OctetString with insufficient data (only tag/len). */
302 		.asn1 = {0x24, 0x04},
303 		.asn1_len = 2,
304 		.asn1_hdr_len = 2,
305 		.want_ret = 0xa0,
306 		.want_length = 4,
307 		.want_tag = 4,
308 		.want_class = 0,
309 		.want_error = ASN1_R_TOO_LONG,
310 	},
311 };
312 
313 #define N_ASN1_GET_OBJECT_TESTS \
314     (sizeof(asn1_get_object_tests) / sizeof(*asn1_get_object_tests))
315 
316 static int
asn1_get_object(void)317 asn1_get_object(void)
318 {
319 	const struct asn1_get_object_test *agot;
320 	const uint8_t *p;
321 	int ret, tag, tag_class;
322 	long err, length;
323 	size_t i;
324 	int failed = 1;
325 
326 	for (i = 0; i < N_ASN1_GET_OBJECT_TESTS; i++) {
327 		agot = &asn1_get_object_tests[i];
328 
329 		ERR_clear_error();
330 
331 		p = agot->asn1;
332 		ret = ASN1_get_object(&p, &length, &tag, &tag_class, agot->asn1_len);
333 
334 		if (ret != agot->want_ret) {
335 			fprintf(stderr, "FAIL: %zu - got return value %x, want %x\n",
336 			    i, ret, agot->want_ret);
337 			goto failed;
338 		}
339 		if (ret & 0x80) {
340 			err = ERR_peek_error();
341 			if (ERR_GET_REASON(err) != agot->want_error) {
342 				fprintf(stderr, "FAIL: %zu - got error reason %d, "
343 				    "want %d\n", i, ERR_GET_REASON(err),
344 				    agot->want_error);
345 				goto failed;
346 			}
347 			if (ERR_GET_REASON(err) == ASN1_R_HEADER_TOO_LONG) {
348 				if (p != agot->asn1) {
349 					fprintf(stderr, "FAIL: %zu - got ber_in %p, "
350 					    "want %p\n", i, p, agot->asn1);
351 					goto failed;
352 				}
353 				continue;
354 			}
355 		}
356 		if (length != agot->want_length) {
357 			fprintf(stderr, "FAIL: %zu - got length %ld, want %ld\n",
358 			    i, length, agot->want_length);
359 			goto failed;
360 		}
361 		if (tag != agot->want_tag) {
362 			fprintf(stderr, "FAIL: %zu - got tag %d, want %d\n",
363 			    i, tag, agot->want_tag);
364 			goto failed;
365 		}
366 		if (tag_class != agot->want_class) {
367 			fprintf(stderr, "FAIL: %zu - got class %d, want %d\n",
368 			    i, tag_class, agot->want_class);
369 			goto failed;
370 		}
371 		if (p != agot->asn1 + agot->asn1_hdr_len) {
372 			fprintf(stderr, "FAIL: %zu - got ber_in %p, want %p\n",
373 			    i, p, agot->asn1 + agot->asn1_len);
374 			goto failed;
375 		}
376 	}
377 
378 	failed = 0;
379 
380  failed:
381 	return failed;
382 }
383 
384 static int
asn1_integer_get_null_test(void)385 asn1_integer_get_null_test(void)
386 {
387 	int failed = 0;
388 	long ret;
389 
390 	if ((ret = ASN1_INTEGER_get(NULL)) != 0) {
391 		fprintf(stderr, "FAIL: ASN1_INTEGER_get(NULL) %ld != 0\n", ret);
392 		failed |= 1;
393 	}
394 
395 	if ((ret = ASN1_ENUMERATED_get(NULL)) != 0) {
396 		fprintf(stderr, "FAIL: ASN1_ENUMERATED_get(NULL) %ld != 0\n",
397 		    ret);
398 		failed |= 1;
399 	}
400 
401 	return failed;
402 }
403 
404 int
main(int argc,char ** argv)405 main(int argc, char **argv)
406 {
407 	int failed = 0;
408 
409 	failed |= asn1_tag2bit();
410 	failed |= asn1_tag2str();
411 	failed |= asn1_get_object();
412 	failed |= asn1_integer_get_null_test();
413 
414 	return (failed);
415 }
416