1/* $OpenBSD: ber_test.c,v 1.20 2019/10/24 12:39:26 tb Exp $
2*/
3/*
4 * Copyright (c) Rob Pierce <rob@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 <sys/types.h>
20
21#include <ber.h>
22#include <errno.h>
23#include <stdio.h>
24#include <string.h>
25
26#define SUCCEED	0
27#define FAIL	1
28
29struct test_vector {
30	int		 fail;		/* 1 means test is expected to fail */
31	int		 memcheck;	/* 1 when short forms used */
32	char		 title[128];
33	size_t		 length;
34	unsigned char	 input[1024];
35};
36
37struct test_vector test_vectors[] = {
38	{
39		SUCCEED,
40		1,
41		"boolean",
42		3,
43		{
44			0x01, 0x01, 0xff
45		},
46	},
47	{
48		FAIL,
49		0,
50		"boolean (constructed - expected failure)",
51		3,
52		{
53			0x21, 0x01, 0xff
54		},
55	},
56	{
57		FAIL,
58		0,
59		"boolean (more than 1 content octet - expected failure)",
60		4,
61		{
62			0x01, 0x02, 0x00, 0xff
63		},
64	},
65	{
66		SUCCEED,
67		1,
68		"enum",
69		3,
70		{
71			0x0a, 0x01, 0x00
72		},
73	},
74	{
75		FAIL,
76		0,
77		"enum (constructed - expected failure)",
78		3,
79		{
80			0x2a, 0x01, 0x00
81		},
82	},
83	{
84		FAIL,
85		0,
86		"enum minimal contents octets (expected failure)",
87		4,
88		{
89			0x0a, 0x02, 0x00, 0x01
90		},
91	},
92	{
93		SUCCEED,
94		1,
95		"integer (zero)",
96		3,
97		{
98			0x02, 0x01, 0x00
99		},
100	},
101	{
102		FAIL,
103		0,
104		"integer (constructed - expected failure)",
105		3,
106		{
107			0x22, 0x01, 0x01
108		},
109	},
110	{
111		SUCCEED,
112		1,
113		"positive integer",
114		3,
115		{
116			0x02, 0x01, 0x63
117		},
118	},
119	{
120		SUCCEED,
121		1,
122		"large positive integer",
123		5,
124		{
125			0x02, 0x03, 0x01, 0x00, 0x00
126		},
127	},
128	{
129		SUCCEED,
130		1,
131		"negative integer",
132		4,
133		{
134			0x02, 0x02, 0xff, 0x7f
135		},
136	},
137	{
138		FAIL,
139		0,
140		"integer minimal contents octets (expected failure)",
141		4,
142		{
143			0x02, 0x02, 0x00, 0x01
144		},
145	},
146	{
147		SUCCEED,
148		1,
149		"bit string",
150		6,
151		{
152			0x03, 0x04, 0xde, 0xad, 0xbe, 0xef
153		},
154	},
155	{
156		SUCCEED,
157		1,
158		"octet string",
159		10,
160		{
161			0x04, 0x08, 0x01, 0x23, 0x45,
162			0x67, 0x89, 0xab, 0xcd, 0xef
163		},
164	},
165	{
166		SUCCEED,
167		1,
168		"null",
169		2,
170		{
171			0x05, 0x00
172		},
173	},
174	{
175		FAIL,
176		0,
177		"null (constructed - expected failure)",
178		2,
179		{
180			0x25, 0x00
181		},
182	},
183	{
184		SUCCEED,
185		1,
186		"object identifier",
187		8,
188		{
189			0x06, 0x06, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d
190		}
191	},
192	{
193		SUCCEED,
194		1,
195		"sequence",	/* ldap */
196		14,
197		{
198			0x30, 0x0c, 0x02, 0x01, 0x01, 0x60, 0x07, 0x02,
199			0x01, 0x03, 0x04, 0x00, 0x80, 0x00
200		}
201	},
202	{
203		SUCCEED,
204		1,
205		"ldap bind",
206		30,
207		{
208			0x30, 0x1c, 0x02, 0x01, 0x01, 0x60, 0x17, 0x02,
209			0x01, 0x03, 0x04, 0x08, 0x63, 0x6e, 0x3d, 0x61,
210			0x64, 0x6d, 0x69, 0x6e, 0x80, 0x08, 0x70, 0x61,
211			0x73, 0x73, 0x77, 0x6f, 0x72, 0x64
212		}
213	},
214	{
215		SUCCEED,
216		1,
217		"ldap search",
218		37,
219		{
220			0x30, 0x23, 0x02, 0x01, 0x01, 0x60, 0x1e, 0x04,
221 			0x09, 0x6f, 0x75, 0x3d, 0x70, 0x65, 0x6f, 0x70,
222			0x6c, 0x65, 0x0a, 0x01, 0x00, 0x0a, 0x01, 0x00,
223			0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x01, 0x01,
224			0x00, 0x04, 0x02, 0x63, 0x6e
225		}
226	},
227	{
228		SUCCEED,
229		1,
230		"snmpd encode",
231		15,
232		{
233			0x30, 0x0d, 0x02, 0x01, 0x01, 0x02, 0x02, 0x20,
234			0x00, 0x04, 0x01, 0x01, 0x02, 0x01, 0x03
235		}
236	},
237	{
238		SUCCEED,
239		1,
240		"set with integer and boolean",
241		8,
242		{
243			0x31, 0x06, 0x02, 0x01, 0x04, 0x01, 0x01, 0xff
244		}
245	},
246	{
247		FAIL,
248		0,
249		"indefinite encoding (expected failure)",
250		4,
251		{
252			0x30, 0x80, 0x00, 0x00
253		}
254	},
255	{
256		FAIL,
257		0,
258		"reserved for future use (expected failure)",
259		4,
260		{
261			0x30, 0xff, 0x01, 0x01
262		}
263	},
264	{
265		FAIL,
266		0,
267		"long form tagging prohibited (expected failure)",
268		5,
269		{
270			0x1f, 0x80, 0x02, 0x01, 0x01
271		},
272	},
273	{
274		SUCCEED,
275		0,
276		"max long form length octets (i.e. 4 bytes)",
277		7,
278		{
279			0x02, 0x84, 0x00, 0x00, 0x00, 0x01, 0x01
280		},
281	},
282	{
283		FAIL,
284		0,
285		"overflow long form length octets (expected failure)",
286		8,
287		{
288			0x02, 0x85, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01
289		},
290	},
291	{
292		FAIL,
293		0,
294		"incorrect length - not enough data (expected failure)",
295		3,
296		{
297			0x02, 0x02, 0x01
298		}
299	}
300};
301
302static void
303hexdump(const unsigned char *buf, size_t len)
304{
305	size_t	i;
306
307	for (i = 1; i < len; i++)
308		fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "": "\n");
309
310	fprintf(stderr, " 0x%02hhx", buf[i - 1]);
311	fprintf(stderr, "\n");
312}
313
314unsigned int
315ldap_application(struct ber_element *elm)
316{
317	return BER_TYPE_OCTETSTRING;
318}
319
320static int
321test(int i)
322{
323	int			 pos, b;
324	char			*string;
325	void			*p = NULL;
326	ssize_t			 len = 0;
327	struct ber_element	*elm = NULL, *ptr = NULL;
328	struct ber		 ber;
329	long long		 val;
330	void			*bstring = NULL;
331	struct ber_oid		 oid;
332	struct ber_octetstring	 ostring;
333
334	bzero(&ber, sizeof(ber));
335	ober_set_readbuf(&ber, test_vectors[i].input, test_vectors[i].length);
336	ober_set_application(&ber, ldap_application);
337
338	elm = ober_read_elements(&ber, elm);
339	if (elm == NULL && test_vectors[i].fail &&
340	    (errno == EINVAL || errno == ERANGE || errno == ECANCELED))
341		return 0;
342	else if (elm != NULL && test_vectors[i].fail) {
343		printf("expected failure of ober_read_elements did not occur\n");
344		return 1;
345	} else if (elm == NULL) {
346		printf("unexpectedly failed ober_read_elements\n");
347		return 1;
348	}
349
350	/*
351	 * short form tagged elements start at the 3rd octet (i.e. position 2).
352	 */
353	if (test_vectors[i].memcheck) {
354		pos = ober_getpos(elm);
355		if (pos != 2) {
356			printf("unexpected element position within "
357			    "byte stream\n");
358			return 1;
359		}
360	}
361
362	switch (elm->be_encoding) {
363	case BER_TYPE_EOC:
364		if (ober_get_eoc(elm) == -1) {
365			printf("failed (eoc) encoding check\n");
366			return 1;
367		}
368		if (ober_scanf_elements(elm, ".", &val) == -1) {
369			printf("failed (eoc) ober_scanf_elements\n");
370			return 1;
371		}
372		break;
373	case BER_TYPE_BOOLEAN:
374		if (ober_get_boolean(elm, &b) == -1) {
375			printf("failed (boolean) encoding check\n");
376			return 1;
377		}
378		if (ober_scanf_elements(elm, "b", &b) == -1) {
379			printf("failed (boolean) ober_scanf_elements\n");
380			return 1;
381		}
382		break;
383	case BER_TYPE_INTEGER:
384		if (ober_get_integer(elm, &val) == -1) {
385			printf("failed (int) encoding check\n");
386			return 1;
387		}
388		if (ober_scanf_elements(elm, "i", &val) == -1) {
389			printf("failed (int) ober_scanf_elements (i)\n");
390			return 1;
391		}
392		if (ober_scanf_elements(elm, "d", &val) == -1) {
393			printf("failed (int) ober_scanf_elements (d)\n");
394			return 1;
395		}
396		break;
397	case BER_TYPE_ENUMERATED:
398		if (ober_get_enumerated(elm, &val) == -1) {
399			printf("failed (enum) encoding check\n");
400			return 1;
401		}
402		if (ober_scanf_elements(elm, "E", &val) == -1) {
403			printf("failed (enum) ober_scanf_elements (E)\n");
404			return 1;
405		}
406		break;
407	case BER_TYPE_BITSTRING:
408		if (ober_get_bitstring(elm, &bstring, &len) == -1) {
409			printf("failed (bit string) encoding check\n");
410			return 1;
411		}
412		break;
413	case BER_TYPE_OCTETSTRING:
414		if (ober_get_ostring(elm, &ostring) == -1) {
415			printf("failed (octet string) encoding check\n");
416			return 1;
417		}
418		if (ober_scanf_elements(elm, "s", &string) == -1) {
419			printf("failed (octet string) ober_scanf_elements\n");
420			return 1;
421		}
422		break;
423	case BER_TYPE_NULL:
424		if (ober_get_null(elm) == -1) {
425			printf("failed (null) encoding check\n");
426			return 1;
427		}
428		if (ober_scanf_elements(elm, "0", &val) == -1) {
429			printf("failed (null) ober_scanf_elements\n");
430			return 1;
431		}
432		break;
433	case BER_TYPE_OBJECT:	/* OID */
434		if (ober_get_oid(elm, &oid) == -1) {
435			printf("failed (oid) encoding check\n");
436			return 1;
437		}
438		if (ober_scanf_elements(elm, "o", &oid) == -1) {
439			printf("failed (oid) ober_scanf_elements\n");
440			return 1;
441		}
442		break;
443	case BER_TYPE_SET:
444	case BER_TYPE_SEQUENCE:
445		if (elm->be_sub != NULL) {
446			ptr = elm->be_sub;
447			if (ober_getpos(ptr) <= pos) {
448				printf("unexpected element position within "
449				    "byte stream\n");
450				return 1;
451			}
452		} else {
453			printf("expected sub element was not present\n");
454			return 1;
455		}
456		break;
457	default:
458		printf("failed with unknown encoding (%ud)\n",
459		    elm->be_encoding);
460		return 1;
461	}
462
463	/*
464	 * additional testing on short form encoding
465	 */
466	if (test_vectors[i].memcheck) {
467		len = ober_calc_len(elm);
468		if (len != test_vectors[i].length) {
469			printf("failed to calculate length\n");
470			return 1;
471		}
472
473		ber.br_wbuf = NULL;
474		len = ober_write_elements(&ber, elm);
475		if (len != test_vectors[i].length) {
476			printf("failed length check (was %zd want "
477			    "%zd)\n", len, test_vectors[i].length);
478			return 1;
479		}
480
481		if (memcmp(ber.br_wbuf, test_vectors[i].input,
482		    test_vectors[i].length) != 0) {
483			printf("failed byte stream compare\n");
484			printf("Got:\n");
485			hexdump(ber.br_wbuf, len);
486			printf("Expected:\n");
487			hexdump(test_vectors[i].input, test_vectors[i].length);
488			return 1;
489		}
490		ober_free(&ber);
491
492	}
493	ober_free_elements(elm);
494
495	return 0;
496}
497
498int
499test_ber_printf_elements_integer(void) {
500	int			 val = 1, len = 0;
501	struct ber_element	*elm = NULL;
502	struct ber		 ber;
503
504	unsigned char		 exp[3] = { 0x02, 0x01, 0x01 };
505
506	elm = ober_printf_elements(elm, "d", val);
507	if (elm == NULL) {
508		printf("failed ober_printf_elements\n");
509		return 1;
510	}
511
512	bzero(&ber, sizeof(ber));
513	ber.br_wbuf = NULL;
514	len = ober_write_elements(&ber, elm);
515	if (len != sizeof(exp)) {
516		printf("failed length check (was %d want %zd)\n", len,
517		    sizeof(exp));
518		return 1;
519	}
520
521	if (memcmp(ber.br_wbuf, exp, len) != 0) {
522		printf("failed (int) byte stream compare\n");
523		return 1;
524	}
525
526	ober_free_elements(elm);
527	ober_free(&ber);
528	return 0;
529}
530
531#define LDAP_REQ_BIND		0
532#define LDAP_REQ_SEARCH		0
533#define VERSION			3
534#define	LDAP_AUTH_SIMPLE	0
535
536int
537test_ber_printf_elements_ldap_bind(void) {
538	int			 len = 0, msgid = 1;
539	char			*binddn = "cn=admin";
540	char			*bindcred = "password";
541	struct ber_element	*root = NULL, *elm = NULL;
542	struct ber		 ber;
543
544	unsigned char		 exp[] = {
545		0x30, 0x1c,
546		0x02, 0x01, 0x01,
547		0x60, 0x17,
548		0x02, 0x01, 0x03,
549		0x04, 0x08, 0x63, 0x6e, 0x3d, 0x61, 0x64, 0x6d, 0x69, 0x6e,
550		0x80, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64
551	};
552
553	if ((root = ober_add_sequence(NULL)) == NULL)
554		return 1;
555
556	elm = ober_printf_elements(root, "d{tdsst", msgid,
557	    BER_CLASS_APP, LDAP_REQ_BIND,
558	    VERSION,
559	    binddn, bindcred,
560	    BER_CLASS_CONTEXT, LDAP_AUTH_SIMPLE);
561
562	if (elm == NULL) {
563		printf("failed ober_printf_elements\n");
564		return 1;
565	}
566
567	bzero(&ber, sizeof(ber));
568	ber.br_wbuf = NULL;
569	ober_set_application(&ber, ldap_application);
570	len = ober_write_elements(&ber, root);
571	if (len != sizeof(exp)) {
572		printf("failed length check (was %d want %zd)\n", len,
573		    sizeof(exp));
574		return 1;
575	}
576
577	if (memcmp(ber.br_wbuf, exp, len) != 0) {
578		printf("failed (ldap bind) byte stream compare\n");
579		hexdump(ber.br_wbuf, len);
580		return 1;
581	}
582
583	ober_free_elements(elm);
584	ober_free(&ber);
585	return 0;
586}
587
588int
589test_ber_printf_elements_ldap_search(void) {
590	int			 len = 0, msgid = 1;
591	int			 sizelimit = 0, timelimit = 0;
592	int			 typesonly = 0;
593	long long		 scope = 0, deref = 0;
594	char			*basedn = "ou=people";
595	char			*filter = "cn";
596	struct ber_element	*root = NULL, *elm = NULL, *felm = NULL;
597	struct ber		 ber;
598
599	unsigned char		 exp[] = {
600		0x30, 0x23, 0x02, 0x01, 0x01, 0x60, 0x1e, 0x04,
601		0x09, 0x6f, 0x75, 0x3d, 0x70, 0x65, 0x6f, 0x70,
602		0x6c, 0x65, 0x0a, 0x01, 0x00, 0x0a, 0x01, 0x00,
603		0x02, 0x01, 0x00, 0x02, 0x01, 0x00, 0x01, 0x01,
604		0x00, 0x04, 0x02, 0x63, 0x6e
605	};
606
607	if ((root = ober_add_sequence(NULL)) == NULL)
608		return 1;
609
610	elm = ober_printf_elements(root, "d{tsEEddbs",
611	    msgid, BER_CLASS_APP, LDAP_REQ_SEARCH,
612	    basedn, scope, deref, sizelimit, timelimit, typesonly, filter);
613	if (elm == NULL) {
614		printf("failed ober_printf_elements\n");
615		return 1;
616	}
617
618	bzero(&ber, sizeof(ber));
619	ber.br_wbuf = NULL;
620	ober_set_application(&ber, ldap_application);
621	len = ober_write_elements(&ber, root);
622	if (len != sizeof(exp)) {
623		printf("failed length check (was %d want %zd)\n", len,
624		    sizeof(exp));
625		return 1;
626	}
627
628	if (memcmp(ber.br_wbuf, exp, len) != 0) {
629		printf("failed (ldap search) byte stream compare\n");
630		hexdump(ber.br_wbuf, len);
631		return 1;
632	}
633
634	ober_free_elements(elm);
635	ober_free(&ber);
636	return 0;
637}
638
639int
640test_ber_printf_elements_snmp_v3_encode(void) {
641	int			 len = 0;
642	u_int8_t		 f = 0x01;	/* verbose */
643	long long		 secmodel = 3;	/* USM */
644	long long		 msgid = 1, max_msg_size = 8192;
645	struct ber_element	*elm = NULL;
646	struct ber		 ber;
647
648	unsigned char		 exp[] = {
649		0x30, 0x0d, 0x02, 0x01, 0x01, 0x02, 0x02, 0x20,
650		0x00, 0x04, 0x01, 0x01, 0x02, 0x01, 0x03
651	};
652
653	elm = ober_printf_elements(elm, "{iixi}", msgid, max_msg_size,
654	    &f, sizeof(f), secmodel);
655	if (elm == NULL) {
656		printf("failed ober_printf_elements\n");
657		return 1;
658	}
659
660	bzero(&ber, sizeof(ber));
661	ber.br_wbuf = NULL;
662	len = ober_write_elements(&ber, elm);
663	if (len != sizeof(exp)) {
664		printf("failed length check (was %d want %zd)\n", len,
665		    sizeof(exp));
666		return 1;
667	}
668
669	if (memcmp(ber.br_wbuf, exp, len) != 0) {
670		printf("failed (snmp_v3_encode) byte stream compare\n");
671		hexdump(ber.br_wbuf, len);
672		return 1;
673	}
674
675	ober_free_elements(elm);
676	ober_free(&ber);
677	return 0;
678}
679
680int
681test_ber_null(void)
682{
683	long long		 val;
684	struct ber_element	*elm = NULL;
685
686	/* scanning into a null ber_element should fail */
687	if (ober_scanf_elements(elm, "0", &val) != -1) {
688		printf("failed (null ber_element) ober_scanf_elements empty\n");
689		goto fail;
690	}
691
692	if ((elm = ober_printf_elements(elm, "{d}", 1)) == NULL) {
693		printf("failed (null ber_element) ober_printf_elements\n");
694	}
695
696	/*
697	 * Scanning after the last valid element should be able to descend back
698	 * into the parent level.
699	 */
700	if (ober_scanf_elements(elm, "{i}", &val) != 0) {
701		printf("failed (null ber_element) ober_scanf_elements valid\n");
702		goto fail;
703	}
704	/*
705	 * Scanning for a non-existent element should fail, even if it's just a
706	 * skip.
707	 */
708	if (ober_scanf_elements(elm, "{lS}", &val) != -1) {
709		printf("failed (null ber_element) ober_scanf_elements invalid\n");
710		goto fail;
711	}
712
713	ober_free_elements(elm);
714	return 0;
715
716fail:
717	ober_free_elements(elm);
718	return 1;
719}
720
721int
722main(void)
723{
724	extern char *__progname;
725
726	ssize_t		len = 0;
727	int		i, ret = 0;
728
729	/*
730	 * drive test vectors for ber byte stream input validation, etc.
731	 */
732	for (i = 0; i < sizeof(test_vectors) / sizeof(test_vectors[0]); i++) {
733		if (test(i) != 0) {
734			printf("FAILED: %s\n", test_vectors[i].title);
735			ret = 1;
736		} else
737			printf("SUCCESS: %s\n", test_vectors[i].title);
738	}
739
740	/*
741	 * run standalone functions for ber byte stream creation, etc.
742	 * (e.g. ldap, snmpd)
743	 */
744	if (test_ber_printf_elements_integer() != 0) {
745		printf("FAILED: test_ber_printf_elements_integer\n");
746		ret = 1;
747	} else
748		printf("SUCCESS: test_ber_printf_elements_integer\n");
749
750	if (test_ber_printf_elements_ldap_bind() != 0) {
751		printf("FAILED: test_ber_printf_elements_ldap_bind\n");
752		ret = 1;
753	} else
754		printf("SUCCESS: test_ber_printf_elements_ldap_bind\n");
755
756	if (test_ber_printf_elements_ldap_search() != 0) {
757		printf("FAILED: test_ber_printf_elements_ldap_search\n");
758		ret = 1;
759	} else
760		printf("SUCCESS: test_ber_printf_elements_ldap_search\n");
761
762	if (test_ber_printf_elements_snmp_v3_encode() != 0) {
763		printf("FAILED: test_ber_printf_elements_snmpd_v3_encode\n");
764		ret = 1;
765	} else
766		printf("SUCCESS: test_ber_printf_elements_snmpd_v3_encode\n");
767
768	if (test_ber_null() != 0) {
769		printf("FAILED: test_ber_null\n");
770		ret = 1;
771	} else
772		printf("SUCCESS: test_ber_null\n");
773
774	if (ret != 0) {
775		printf("FAILED: %s\n", __progname);
776		return 1;
777	}
778
779	return 0;
780}
781