1/*	$OpenBSD: ber.c,v 1.9 2015/02/12 00:30:38 pelikan Exp $ */
2/*	$FreeBSD$ */
3
4/*
5 * Copyright (c) 2007 Reyk Floeter <reyk@vantronix.net>
6 * Copyright (c) 2006, 2007 Claudio Jeker <claudio@openbsd.org>
7 * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22#include <sys/types.h>
23
24#include <errno.h>
25#include <limits.h>
26#include <stdlib.h>
27#include <err.h>	/* XXX for debug output */
28#include <stdio.h>	/* XXX for debug output */
29#include <string.h>
30#include <unistd.h>
31#include <stdarg.h>
32
33#include "ber.h"
34
35#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
36
37#define BER_TYPE_CONSTRUCTED	0x20	/* otherwise primitive */
38#define BER_TYPE_SINGLE_MAX	30
39#define BER_TAG_MASK		0x1f
40#define BER_TAG_MORE		0x80	/* more subsequent octets */
41#define BER_TAG_TYPE_MASK	0x7f
42#define BER_CLASS_SHIFT		6
43
44static int	ber_dump_element(struct ber *ber, struct ber_element *root);
45static void	ber_dump_header(struct ber *ber, struct ber_element *root);
46static void	ber_putc(struct ber *ber, u_char c);
47static void	ber_write(struct ber *ber, void *buf, size_t len);
48static ssize_t	get_id(struct ber *b, unsigned long *tag, int *class,
49    int *cstruct);
50static ssize_t	get_len(struct ber *b, ssize_t *len);
51static ssize_t	ber_read_element(struct ber *ber, struct ber_element *elm);
52static ssize_t	ber_readbuf(struct ber *b, void *buf, size_t nbytes);
53static ssize_t	ber_getc(struct ber *b, u_char *c);
54static ssize_t	ber_read(struct ber *ber, void *buf, size_t len);
55
56#ifdef DEBUG
57#define DPRINTF(...)	printf(__VA_ARGS__)
58#else
59#define DPRINTF(...)	do { } while (0)
60#endif
61
62struct ber_element *
63ber_get_element(unsigned long encoding)
64{
65	struct ber_element *elm;
66
67	if ((elm = calloc(1, sizeof(*elm))) == NULL)
68		return NULL;
69
70	elm->be_encoding = encoding;
71	ber_set_header(elm, BER_CLASS_UNIVERSAL, BER_TYPE_DEFAULT);
72
73	return elm;
74}
75
76void
77ber_set_header(struct ber_element *elm, int class, unsigned long type)
78{
79	elm->be_class = class & BER_CLASS_MASK;
80	if (type == BER_TYPE_DEFAULT)
81		type = elm->be_encoding;
82	elm->be_type = type;
83}
84
85void
86ber_link_elements(struct ber_element *prev, struct ber_element *elm)
87{
88	if (prev != NULL) {
89		if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
90		    prev->be_encoding == BER_TYPE_SET) &&
91		    prev->be_sub == NULL)
92			prev->be_sub = elm;
93		else
94			prev->be_next = elm;
95	}
96}
97
98struct ber_element *
99ber_unlink_elements(struct ber_element *prev)
100{
101	struct ber_element *elm;
102
103	if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
104	    prev->be_encoding == BER_TYPE_SET) &&
105	    prev->be_sub != NULL) {
106		elm = prev->be_sub;
107		prev->be_sub = NULL;
108	} else {
109		elm = prev->be_next;
110		prev->be_next = NULL;
111	}
112
113	return (elm);
114}
115
116void
117ber_replace_elements(struct ber_element *prev, struct ber_element *new)
118{
119	struct ber_element *ber, *next;
120
121	ber = ber_unlink_elements(prev);
122	next = ber_unlink_elements(ber);
123	ber_link_elements(new, next);
124	ber_link_elements(prev, new);
125
126	/* cleanup old element */
127	ber_free_elements(ber);
128}
129
130struct ber_element *
131ber_add_sequence(struct ber_element *prev)
132{
133	struct ber_element *elm;
134
135	if ((elm = ber_get_element(BER_TYPE_SEQUENCE)) == NULL)
136		return NULL;
137
138	ber_link_elements(prev, elm);
139
140	return elm;
141}
142
143struct ber_element *
144ber_add_set(struct ber_element *prev)
145{
146	struct ber_element *elm;
147
148	if ((elm = ber_get_element(BER_TYPE_SET)) == NULL)
149		return NULL;
150
151	ber_link_elements(prev, elm);
152
153	return elm;
154}
155
156struct ber_element *
157ber_add_enumerated(struct ber_element *prev, long long val)
158{
159	struct ber_element *elm;
160	u_int i, len = 0;
161	u_char cur, last = 0;
162
163	if ((elm = ber_get_element(BER_TYPE_ENUMERATED)) == NULL)
164		return NULL;
165
166	elm->be_numeric = val;
167
168	for (i = 0; i < sizeof(long long); i++) {
169		cur = val & 0xff;
170		if (cur != 0 && cur != 0xff)
171			len = i;
172		if ((cur == 0 && last & 0x80) ||
173		    (cur == 0xff && (last & 0x80) == 0))
174			len = i;
175		val >>= 8;
176		last = cur;
177	}
178	elm->be_len = len + 1;
179
180	ber_link_elements(prev, elm);
181
182	return elm;
183}
184
185struct ber_element *
186ber_add_integer(struct ber_element *prev, long long val)
187{
188	struct ber_element *elm;
189	u_int i, len = 0;
190	u_char cur, last = 0;
191
192	if ((elm = ber_get_element(BER_TYPE_INTEGER)) == NULL)
193		return NULL;
194
195	elm->be_numeric = val;
196
197	for (i = 0; i < sizeof(long long); i++) {
198		cur = val & 0xff;
199		if (cur != 0 && cur != 0xff)
200			len = i;
201		if ((cur == 0 && last & 0x80) ||
202		    (cur == 0xff && (last & 0x80) == 0))
203			len = i;
204		val >>= 8;
205		last = cur;
206	}
207	elm->be_len = len + 1;
208
209	ber_link_elements(prev, elm);
210
211	return elm;
212}
213
214int
215ber_get_integer(struct ber_element *elm, long long *n)
216{
217	if (elm->be_encoding != BER_TYPE_INTEGER)
218		return -1;
219
220	*n = elm->be_numeric;
221	return 0;
222}
223
224int
225ber_get_enumerated(struct ber_element *elm, long long *n)
226{
227	if (elm->be_encoding != BER_TYPE_ENUMERATED)
228		return -1;
229
230	*n = elm->be_numeric;
231	return 0;
232}
233
234
235struct ber_element *
236ber_add_boolean(struct ber_element *prev, int bool)
237{
238	struct ber_element *elm;
239
240	if ((elm = ber_get_element(BER_TYPE_BOOLEAN)) == NULL)
241		return NULL;
242
243	elm->be_numeric = bool ? 0xff : 0;
244	elm->be_len = 1;
245
246	ber_link_elements(prev, elm);
247
248	return elm;
249}
250
251int
252ber_get_boolean(struct ber_element *elm, int *b)
253{
254	if (elm->be_encoding != BER_TYPE_BOOLEAN)
255		return -1;
256
257	*b = !(elm->be_numeric == 0);
258	return 0;
259}
260
261struct ber_element *
262ber_add_string(struct ber_element *prev, const char *string)
263{
264	return ber_add_nstring(prev, string, strlen(string));
265}
266
267struct ber_element *
268ber_add_nstring(struct ber_element *prev, const char *string0, size_t len)
269{
270	struct ber_element *elm;
271	char *string;
272
273	if ((string = calloc(1, len)) == NULL)
274		return NULL;
275	if ((elm = ber_get_element(BER_TYPE_OCTETSTRING)) == NULL) {
276		free(string);
277		return NULL;
278	}
279
280	bcopy(string0, string, len);
281	elm->be_val = string;
282	elm->be_len = len;
283	elm->be_free = 1;		/* free string on cleanup */
284
285	ber_link_elements(prev, elm);
286
287	return elm;
288}
289
290int
291ber_get_string(struct ber_element *elm, char **s)
292{
293	if (elm->be_encoding != BER_TYPE_OCTETSTRING)
294		return -1;
295
296	*s = elm->be_val;
297	return 0;
298}
299
300int
301ber_get_nstring(struct ber_element *elm, void **p, size_t *len)
302{
303	if (elm->be_encoding != BER_TYPE_OCTETSTRING)
304		return -1;
305
306	*p = elm->be_val;
307	*len = elm->be_len;
308	return 0;
309}
310
311struct ber_element *
312ber_add_bitstring(struct ber_element *prev, const void *v0, size_t len)
313{
314	struct ber_element *elm;
315	void *v;
316
317	if ((v = calloc(1, len)) == NULL)
318		return NULL;
319	if ((elm = ber_get_element(BER_TYPE_BITSTRING)) == NULL) {
320		free(v);
321		return NULL;
322	}
323
324	bcopy(v0, v, len);
325	elm->be_val = v;
326	elm->be_len = len;
327	elm->be_free = 1;		/* free string on cleanup */
328
329	ber_link_elements(prev, elm);
330
331	return elm;
332}
333
334int
335ber_get_bitstring(struct ber_element *elm, void **v, size_t *len)
336{
337	if (elm->be_encoding != BER_TYPE_BITSTRING)
338		return -1;
339
340	*v = elm->be_val;
341	*len = elm->be_len;
342	return 0;
343}
344
345struct ber_element *
346ber_add_null(struct ber_element *prev)
347{
348	struct ber_element *elm;
349
350	if ((elm = ber_get_element(BER_TYPE_NULL)) == NULL)
351		return NULL;
352
353	ber_link_elements(prev, elm);
354
355	return elm;
356}
357
358int
359ber_get_null(struct ber_element *elm)
360{
361	if (elm->be_encoding != BER_TYPE_NULL)
362		return -1;
363
364	return 0;
365}
366
367struct ber_element *
368ber_add_eoc(struct ber_element *prev)
369{
370	struct ber_element *elm;
371
372	if ((elm = ber_get_element(BER_TYPE_EOC)) == NULL)
373		return NULL;
374
375	ber_link_elements(prev, elm);
376
377	return elm;
378}
379
380int
381ber_get_eoc(struct ber_element *elm)
382{
383	if (elm->be_encoding != BER_TYPE_EOC)
384		return -1;
385
386	return 0;
387}
388
389size_t
390ber_oid2ber(struct ber_oid *o, u_int8_t *buf, size_t len)
391{
392	u_int32_t	 v;
393	u_int		 i, j = 0, k;
394
395	if (o->bo_n < BER_MIN_OID_LEN || o->bo_n > BER_MAX_OID_LEN ||
396	    o->bo_id[0] > 2 || o->bo_id[1] > 40)
397		return (0);
398
399	v = (o->bo_id[0] * 40) + o->bo_id[1];
400	for (i = 2, j = 0; i <= o->bo_n; v = o->bo_id[i], i++) {
401		for (k = 28; k >= 7; k -= 7) {
402			if (v >= (u_int)(1 << k)) {
403				if (len)
404					buf[j] = v >> k | BER_TAG_MORE;
405				j++;
406			}
407		}
408		if (len)
409			buf[j] = v & BER_TAG_TYPE_MASK;
410		j++;
411	}
412
413	return (j);
414}
415
416int
417ber_string2oid(const char *oidstr, struct ber_oid *o)
418{
419	char			*sp, *p, str[BUFSIZ];
420	const char		*errstr;
421
422	if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
423		return (-1);
424	bzero(o, sizeof(*o));
425
426	/* Parse OID strings in the common forms n.n.n, n_n_n_n, or n-n-n */
427	for (p = sp = str; p != NULL; sp = p) {
428		if ((p = strpbrk(p, "._-")) != NULL)
429			*p++ = '\0';
430		o->bo_id[o->bo_n++] = strtonum(sp, 0, UINT_MAX, &errstr);
431		if (errstr || o->bo_n > BER_MAX_OID_LEN)
432			return (-1);
433	}
434
435	return (0);
436}
437
438struct ber_element *
439ber_add_oid(struct ber_element *prev, struct ber_oid *o)
440{
441	struct ber_element	*elm;
442	u_int8_t		*buf;
443	size_t			 len;
444
445	if ((elm = ber_get_element(BER_TYPE_OBJECT)) == NULL)
446		return (NULL);
447
448	if ((len = ber_oid2ber(o, NULL, 0)) == 0)
449		goto fail;
450
451	if ((buf = calloc(1, len)) == NULL)
452		goto fail;
453
454	elm->be_val = buf;
455	elm->be_len = len;
456	elm->be_free = 1;
457
458	if (ber_oid2ber(o, buf, len) != len)
459		goto fail;
460
461	ber_link_elements(prev, elm);
462
463	return (elm);
464
465 fail:
466	ber_free_elements(elm);
467	return (NULL);
468}
469
470struct ber_element *
471ber_add_noid(struct ber_element *prev, struct ber_oid *o, int n)
472{
473	struct ber_oid		 no;
474
475	if (n > BER_MAX_OID_LEN)
476		return (NULL);
477	no.bo_n = n;
478	bcopy(&o->bo_id, &no.bo_id, sizeof(no.bo_id));
479
480	return (ber_add_oid(prev, &no));
481}
482
483struct ber_element *
484ber_add_oidstring(struct ber_element *prev, const char *oidstr)
485{
486	struct ber_oid		 o;
487
488	if (ber_string2oid(oidstr, &o) == -1)
489		return (NULL);
490
491	return (ber_add_oid(prev, &o));
492}
493
494int
495ber_get_oid(struct ber_element *elm, struct ber_oid *o)
496{
497	u_int8_t	*buf;
498	size_t		 len, i = 0, j = 0;
499
500	if (elm->be_encoding != BER_TYPE_OBJECT)
501		return (-1);
502
503	buf = elm->be_val;
504	len = elm->be_len;
505
506	if (!buf[i])
507		return (-1);
508
509	bzero(o, sizeof(*o));
510	o->bo_id[j++] = buf[i] / 40;
511	o->bo_id[j++] = buf[i++] % 40;
512	for (; i < len && j < BER_MAX_OID_LEN; i++) {
513		o->bo_id[j] = (o->bo_id[j] << 7) + (buf[i] & ~0x80);
514		if (buf[i] & 0x80)
515			continue;
516		j++;
517	}
518	o->bo_n = j;
519
520	return (0);
521}
522
523struct ber_element *
524ber_printf_elements(struct ber_element *ber, char *fmt, ...)
525{
526	va_list			 ap;
527	int			 d, class;
528	size_t			 len;
529	unsigned long		 type;
530	long long		 i;
531	char			*s;
532	void			*p;
533	struct ber_oid		*o;
534	struct ber_element	*sub = ber, *e;
535
536	va_start(ap, fmt);
537	while (*fmt) {
538		switch (*fmt++) {
539		case 'B':
540			p = va_arg(ap, void *);
541			len = va_arg(ap, size_t);
542			if ((ber = ber_add_bitstring(ber, p, len)) == NULL)
543				goto fail;
544			break;
545		case 'b':
546			d = va_arg(ap, int);
547			if ((ber = ber_add_boolean(ber, d)) == NULL)
548				goto fail;
549			break;
550		case 'd':
551			d = va_arg(ap, int);
552			if ((ber = ber_add_integer(ber, d)) == NULL)
553				goto fail;
554			break;
555		case 'e':
556			e = va_arg(ap, struct ber_element *);
557			ber_link_elements(ber, e);
558			break;
559		case 'E':
560			i = va_arg(ap, long long);
561			if ((ber = ber_add_enumerated(ber, i)) == NULL)
562				goto fail;
563			break;
564		case 'i':
565			i = va_arg(ap, long long);
566			if ((ber = ber_add_integer(ber, i)) == NULL)
567				goto fail;
568			break;
569		case 'O':
570			o = va_arg(ap, struct ber_oid *);
571			if ((ber = ber_add_oid(ber, o)) == NULL)
572				goto fail;
573			break;
574		case 'o':
575			s = va_arg(ap, char *);
576			if ((ber = ber_add_oidstring(ber, s)) == NULL)
577				goto fail;
578			break;
579		case 's':
580			s = va_arg(ap, char *);
581			if ((ber = ber_add_string(ber, s)) == NULL)
582				goto fail;
583			break;
584		case 't':
585			class = va_arg(ap, int);
586			type = va_arg(ap, unsigned long);
587			ber_set_header(ber, class, type);
588			break;
589		case 'x':
590			s = va_arg(ap, char *);
591			len = va_arg(ap, size_t);
592			if ((ber = ber_add_nstring(ber, s, len)) == NULL)
593				goto fail;
594			break;
595		case '0':
596			if ((ber = ber_add_null(ber)) == NULL)
597				goto fail;
598			break;
599		case '{':
600			if ((ber = sub = ber_add_sequence(ber)) == NULL)
601				goto fail;
602			break;
603		case '(':
604			if ((ber = sub = ber_add_set(ber)) == NULL)
605				goto fail;
606			break;
607		case '}':
608		case ')':
609			ber = sub;
610			break;
611		case '.':
612			if ((e = ber_add_eoc(ber)) == NULL)
613				goto fail;
614			ber = e;
615			break;
616		default:
617			break;
618		}
619	}
620	va_end(ap);
621
622	return (ber);
623 fail:
624	return (NULL);
625}
626
627int
628ber_scanf_elements(struct ber_element *ber, char *fmt, ...)
629{
630#define _MAX_SEQ		 128
631	va_list			 ap;
632	int			*d, level = -1;
633	unsigned long		*t;
634	long long		*i;
635	void			**ptr;
636	size_t			*len, ret = 0, n = strlen(fmt);
637	char			**s;
638	struct ber_oid		*o;
639	struct ber_element	*parent[_MAX_SEQ], **e;
640
641	bzero(parent, sizeof(struct ber_element *) * _MAX_SEQ);
642
643	va_start(ap, fmt);
644	while (*fmt) {
645		switch (*fmt++) {
646		case 'B':
647			ptr = va_arg(ap, void **);
648			len = va_arg(ap, size_t *);
649			if (ber_get_bitstring(ber, ptr, len) == -1)
650				goto fail;
651			ret++;
652			break;
653		case 'b':
654			d = va_arg(ap, int *);
655			if (ber_get_boolean(ber, d) == -1)
656				goto fail;
657			ret++;
658			break;
659		case 'e':
660			e = va_arg(ap, struct ber_element **);
661			*e = ber;
662			ret++;
663			continue;
664		case 'E':
665			i = va_arg(ap, long long *);
666			if (ber_get_enumerated(ber, i) == -1)
667				goto fail;
668			ret++;
669			break;
670		case 'i':
671			i = va_arg(ap, long long *);
672			if (ber_get_integer(ber, i) == -1)
673				goto fail;
674			ret++;
675			break;
676		case 'o':
677			o = va_arg(ap, struct ber_oid *);
678			if (ber_get_oid(ber, o) == -1)
679				goto fail;
680			ret++;
681			break;
682		case 'S':
683			ret++;
684			break;
685		case 's':
686			s = va_arg(ap, char **);
687			if (ber_get_string(ber, s) == -1)
688				goto fail;
689			ret++;
690			break;
691		case 't':
692			d = va_arg(ap, int *);
693			t = va_arg(ap, unsigned long *);
694			*d = ber->be_class;
695			*t = ber->be_type;
696			ret++;
697			continue;
698		case 'x':
699			ptr = va_arg(ap, void **);
700			len = va_arg(ap, size_t *);
701			if (ber_get_nstring(ber, ptr, len) == -1)
702				goto fail;
703			ret++;
704			break;
705		case '0':
706			if (ber->be_encoding != BER_TYPE_NULL)
707				goto fail;
708			ret++;
709			break;
710		case '.':
711			if (ber->be_encoding != BER_TYPE_EOC)
712				goto fail;
713			ret++;
714			break;
715		case '{':
716		case '(':
717			if (ber->be_encoding != BER_TYPE_SEQUENCE &&
718			    ber->be_encoding != BER_TYPE_SET)
719				goto fail;
720			if (ber->be_sub == NULL || level >= _MAX_SEQ-1)
721				goto fail;
722			parent[++level] = ber;
723			ber = ber->be_sub;
724			ret++;
725			continue;
726		case '}':
727		case ')':
728			if (level < 0 || parent[level] == NULL)
729				goto fail;
730			ber = parent[level--];
731			ret++;
732			continue;
733		default:
734			goto fail;
735		}
736
737		if (ber->be_next == NULL)
738			continue;
739		ber = ber->be_next;
740	}
741	va_end(ap);
742	return (ret == n ? 0 : -1);
743
744 fail:
745	va_end(ap);
746	return (-1);
747
748}
749
750/*
751 * write ber elements to the socket
752 *
753 * params:
754 *	ber	holds the socket
755 *	root	fully populated element tree
756 *
757 * returns:
758 *      >=0     number of bytes written
759 *	-1	on failure and sets errno
760 */
761int
762ber_write_elements(struct ber *ber, struct ber_element *root)
763{
764	size_t len;
765
766	/* calculate length because only the definite form is required */
767	len = ber_calc_len(root);
768	DPRINTF("write ber element of %zd bytes length\n", len);
769
770	if (ber->br_wbuf != NULL && ber->br_wbuf + len > ber->br_wend) {
771		free(ber->br_wbuf);
772		ber->br_wbuf = NULL;
773	}
774	if (ber->br_wbuf == NULL) {
775		if ((ber->br_wbuf = malloc(len)) == NULL)
776			return -1;
777		ber->br_wend = ber->br_wbuf + len;
778	}
779
780	/* reset write pointer */
781	ber->br_wptr = ber->br_wbuf;
782
783	if (ber_dump_element(ber, root) == -1)
784		return -1;
785
786	/* XXX this should be moved to a different function */
787	if (ber->fd != -1)
788		return write(ber->fd, ber->br_wbuf, len);
789
790	return (len);
791}
792
793/*
794 * read ber elements from the socket
795 *
796 * params:
797 *	ber	holds the socket and lot more
798 *	root	if NULL, build up an element tree from what we receive on
799 *		the wire. If not null, use the specified encoding for the
800 *		elements received.
801 *
802 * returns:
803 *	!=NULL, elements read and store in the ber_element tree
804 *	NULL, type mismatch or read error
805 */
806struct ber_element *
807ber_read_elements(struct ber *ber, struct ber_element *elm)
808{
809	struct ber_element *root = elm;
810
811	if (root == NULL) {
812		if ((root = ber_get_element(0)) == NULL)
813			return NULL;
814	}
815
816	DPRINTF("read ber elements, root %p\n", root);
817
818	if (ber_read_element(ber, root) == -1) {
819		/* Cleanup if root was allocated by us */
820		if (elm == NULL)
821			ber_free_elements(root);
822		return NULL;
823	}
824
825	return root;
826}
827
828void
829ber_free_elements(struct ber_element *root)
830{
831	if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
832	    root->be_encoding == BER_TYPE_SET))
833		ber_free_elements(root->be_sub);
834	if (root->be_next)
835		ber_free_elements(root->be_next);
836	if (root->be_free && (root->be_encoding == BER_TYPE_OCTETSTRING ||
837	    root->be_encoding == BER_TYPE_BITSTRING ||
838	    root->be_encoding == BER_TYPE_OBJECT))
839		free(root->be_val);
840	free(root);
841}
842
843size_t
844ber_calc_len(struct ber_element *root)
845{
846	unsigned long t;
847	size_t s;
848	size_t size = 2;	/* minimum 1 byte head and 1 byte size */
849
850	/* calculate the real length of a sequence or set */
851	if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
852	    root->be_encoding == BER_TYPE_SET))
853		root->be_len = ber_calc_len(root->be_sub);
854
855	/* fix header length for extended types */
856	if (root->be_type > BER_TYPE_SINGLE_MAX)
857		for (t = root->be_type; t > 0; t >>= 7)
858			size++;
859	if (root->be_len >= BER_TAG_MORE)
860		for (s = root->be_len; s > 0; s >>= 8)
861			size++;
862
863	/* calculate the length of the following elements */
864	if (root->be_next)
865		size += ber_calc_len(root->be_next);
866
867	/* This is an empty element, do not use a minimal size */
868	if (root->be_type == BER_TYPE_EOC && root->be_len == 0)
869		return (0);
870
871	return (root->be_len + size);
872}
873
874/*
875 * internal functions
876 */
877
878static int
879ber_dump_element(struct ber *ber, struct ber_element *root)
880{
881	unsigned long long l;
882	int i;
883	uint8_t u;
884
885	ber_dump_header(ber, root);
886
887	switch (root->be_encoding) {
888	case BER_TYPE_BOOLEAN:
889	case BER_TYPE_INTEGER:
890	case BER_TYPE_ENUMERATED:
891		l = (unsigned long long)root->be_numeric;
892		for (i = root->be_len; i > 0; i--) {
893			u = (l >> ((i - 1) * 8)) & 0xff;
894			ber_putc(ber, u);
895		}
896		break;
897	case BER_TYPE_BITSTRING:
898		return -1;
899	case BER_TYPE_OCTETSTRING:
900	case BER_TYPE_OBJECT:
901		ber_write(ber, root->be_val, root->be_len);
902		break;
903	case BER_TYPE_NULL:	/* no payload */
904	case BER_TYPE_EOC:
905		break;
906	case BER_TYPE_SEQUENCE:
907	case BER_TYPE_SET:
908		if (root->be_sub && ber_dump_element(ber, root->be_sub) == -1)
909			return -1;
910		break;
911	}
912
913	if (root->be_next == NULL)
914		return 0;
915	return ber_dump_element(ber, root->be_next);
916}
917
918static void
919ber_dump_header(struct ber *ber, struct ber_element *root)
920{
921	u_char	id = 0, t, buf[8];
922	unsigned long type;
923	size_t size;
924
925	/* class universal, type encoding depending on type value */
926	/* length encoding */
927	if (root->be_type <= BER_TYPE_SINGLE_MAX) {
928		id = root->be_type | (root->be_class << BER_CLASS_SHIFT);
929		if (root->be_encoding == BER_TYPE_SEQUENCE ||
930		    root->be_encoding == BER_TYPE_SET)
931			id |= BER_TYPE_CONSTRUCTED;
932
933		ber_putc(ber, id);
934	} else {
935		id = BER_TAG_MASK | (root->be_class << BER_CLASS_SHIFT);
936		if (root->be_encoding == BER_TYPE_SEQUENCE ||
937		    root->be_encoding == BER_TYPE_SET)
938			id |= BER_TYPE_CONSTRUCTED;
939
940		ber_putc(ber, id);
941
942		for (t = 0, type = root->be_type; type > 0; type >>= 7)
943			buf[t++] = type & ~BER_TAG_MORE;
944
945		while (t-- > 0) {
946			if (t > 0)
947				buf[t] |= BER_TAG_MORE;
948			ber_putc(ber, buf[t]);
949		}
950	}
951
952	if (root->be_len < BER_TAG_MORE) {
953		/* short form */
954		ber_putc(ber, root->be_len);
955	} else {
956		for (t = 0, size = root->be_len; size > 0; size >>= 8)
957			buf[t++] = size & 0xff;
958
959		ber_putc(ber, t | BER_TAG_MORE);
960
961		while (t > 0)
962			ber_putc(ber, buf[--t]);
963	}
964}
965
966static void
967ber_putc(struct ber *ber, u_char c)
968{
969	if (ber->br_wptr + 1 <= ber->br_wend)
970		*ber->br_wptr = c;
971	ber->br_wptr++;
972}
973
974static void
975ber_write(struct ber *ber, void *buf, size_t len)
976{
977	if (ber->br_wptr + len <= ber->br_wend)
978		bcopy(buf, ber->br_wptr, len);
979	ber->br_wptr += len;
980}
981
982/*
983 * extract a BER encoded tag. There are two types, a short and long form.
984 */
985static ssize_t
986get_id(struct ber *b, unsigned long *tag, int *class, int *cstruct)
987{
988	u_char u;
989	size_t i = 0;
990	unsigned long t = 0;
991
992	if (ber_getc(b, &u) == -1)
993		return -1;
994
995	*class = (u >> BER_CLASS_SHIFT) & BER_CLASS_MASK;
996	*cstruct = (u & BER_TYPE_CONSTRUCTED) == BER_TYPE_CONSTRUCTED;
997
998	if ((u & BER_TAG_MASK) != BER_TAG_MASK) {
999		*tag = u & BER_TAG_MASK;
1000		return 1;
1001	}
1002
1003	do {
1004		if (ber_getc(b, &u) == -1)
1005			return -1;
1006		t = (t << 7) | (u & ~BER_TAG_MORE);
1007		i++;
1008	} while (u & BER_TAG_MORE);
1009
1010	if (i > sizeof(unsigned long)) {
1011		errno = ERANGE;
1012		return -1;
1013	}
1014
1015	*tag = t;
1016	return i + 1;
1017}
1018
1019/*
1020 * extract length of a ber object -- if length is unknown an error is returned.
1021 */
1022static ssize_t
1023get_len(struct ber *b, ssize_t *len)
1024{
1025	u_char	u, n;
1026	ssize_t	s, r;
1027
1028	if (ber_getc(b, &u) == -1)
1029		return -1;
1030	if ((u & BER_TAG_MORE) == 0) {
1031		/* short form */
1032		*len = u;
1033		return 1;
1034	}
1035
1036	n = u & ~BER_TAG_MORE;
1037	if (sizeof(ssize_t) < n) {
1038		errno = ERANGE;
1039		return -1;
1040	}
1041	r = n + 1;
1042
1043	for (s = 0; n > 0; n--) {
1044		if (ber_getc(b, &u) == -1)
1045			return -1;
1046		s = (s << 8) | u;
1047	}
1048
1049	if (s < 0) {
1050		/* overflow */
1051		errno = ERANGE;
1052		return -1;
1053	}
1054
1055	if (s == 0) {
1056		/* invalid encoding */
1057		errno = EINVAL;
1058		return -1;
1059	}
1060
1061	*len = s;
1062	return r;
1063}
1064
1065static ssize_t
1066ber_read_element(struct ber *ber, struct ber_element *elm)
1067{
1068	long long val = 0;
1069	struct ber_element *next;
1070	unsigned long type;
1071	int i, class, cstruct;
1072	ssize_t len, r, totlen = 0;
1073	u_char c;
1074
1075	if ((r = get_id(ber, &type, &class, &cstruct)) == -1)
1076		return -1;
1077	DPRINTF("ber read got class %d type %lu, %s\n",
1078	    class, type, cstruct ? "constructive" : "primitive");
1079	totlen += r;
1080	if ((r = get_len(ber, &len)) == -1)
1081		return -1;
1082	DPRINTF("ber read element size %zd\n", len);
1083	totlen += r + len;
1084
1085	/*
1086	 * If using an external buffer and the total size of the element
1087	 * is larger, then the external buffer don't bother to continue.
1088	 */
1089	if (ber->fd == -1 && len > ber->br_rend - ber->br_rptr) {
1090		errno = ECANCELED;
1091		return -1;
1092	}
1093
1094	elm->be_type = type;
1095	elm->be_len = len;
1096	elm->be_class = class;
1097
1098	if (elm->be_encoding == 0) {
1099		/* try to figure out the encoding via class, type and cstruct */
1100		if (cstruct)
1101			elm->be_encoding = BER_TYPE_SEQUENCE;
1102		else if (class == BER_CLASS_UNIVERSAL)
1103			elm->be_encoding = type;
1104		else if (ber->br_application != NULL) {
1105			/*
1106			 * Ask the application to map the encoding to a
1107			 * universal type. For example, a SMI IpAddress
1108			 * type is defined as 4 byte OCTET STRING.
1109			 */
1110			elm->be_encoding = (*ber->br_application)(elm);
1111		} else
1112			/* last resort option */
1113			elm->be_encoding = BER_TYPE_NULL;
1114	}
1115
1116	switch (elm->be_encoding) {
1117	case BER_TYPE_EOC:	/* End-Of-Content */
1118		break;
1119	case BER_TYPE_BOOLEAN:
1120	case BER_TYPE_INTEGER:
1121	case BER_TYPE_ENUMERATED:
1122		if (len > (ssize_t)sizeof(long long))
1123			return -1;
1124		for (i = 0; i < len; i++) {
1125			if (ber_getc(ber, &c) != 1)
1126				return -1;
1127			val <<= 8;
1128			val |= c;
1129		}
1130
1131		/* sign extend if MSB is set */
1132		if (val >> ((i - 1) * 8) & 0x80)
1133			val |= ULLONG_MAX << (i * 8);
1134		elm->be_numeric = val;
1135		break;
1136	case BER_TYPE_BITSTRING:
1137		elm->be_val = malloc(len);
1138		if (elm->be_val == NULL)
1139			return -1;
1140		elm->be_free = 1;
1141		elm->be_len = len;
1142		ber_read(ber, elm->be_val, len);
1143		break;
1144	case BER_TYPE_OCTETSTRING:
1145	case BER_TYPE_OBJECT:
1146		elm->be_val = malloc(len + 1);
1147		if (elm->be_val == NULL)
1148			return -1;
1149		elm->be_free = 1;
1150		elm->be_len = len;
1151		ber_read(ber, elm->be_val, len);
1152		((u_char *)elm->be_val)[len] = '\0';
1153		break;
1154	case BER_TYPE_NULL:	/* no payload */
1155		if (len != 0)
1156			return -1;
1157		break;
1158	case BER_TYPE_SEQUENCE:
1159	case BER_TYPE_SET:
1160		if (elm->be_sub == NULL) {
1161			if ((elm->be_sub = ber_get_element(0)) == NULL)
1162				return -1;
1163		}
1164		next = elm->be_sub;
1165		while (len > 0) {
1166			r = ber_read_element(ber, next);
1167			if (r == -1)
1168				return -1;
1169			len -= r;
1170			if (len > 0 && next->be_next == NULL) {
1171				if ((next->be_next = ber_get_element(0)) ==
1172				    NULL)
1173					return -1;
1174			}
1175			next = next->be_next;
1176		}
1177		break;
1178	}
1179	return totlen;
1180}
1181
1182static ssize_t
1183ber_readbuf(struct ber *b, void *buf, size_t nbytes)
1184{
1185	size_t	 sz;
1186	size_t	 len;
1187
1188	if (b->br_rbuf == NULL)
1189		return -1;
1190
1191	sz = b->br_rend - b->br_rptr;
1192	len = MINIMUM(nbytes, sz);
1193	if (len == 0) {
1194		errno = ECANCELED;
1195		return (-1);	/* end of buffer and parser wants more data */
1196	}
1197
1198	bcopy(b->br_rptr, buf, len);
1199	b->br_rptr += len;
1200
1201	return (len);
1202}
1203
1204void
1205ber_set_readbuf(struct ber *b, void *buf, size_t len)
1206{
1207	b->br_rbuf = b->br_rptr = buf;
1208	b->br_rend = (u_int8_t *)buf + len;
1209}
1210
1211ssize_t
1212ber_get_writebuf(struct ber *b, void **buf)
1213{
1214	if (b->br_wbuf == NULL)
1215		return -1;
1216	*buf = b->br_wbuf;
1217	return (b->br_wend - b->br_wbuf);
1218}
1219
1220void
1221ber_set_application(struct ber *b, unsigned long (*cb)(struct ber_element *))
1222{
1223	b->br_application = cb;
1224}
1225
1226void
1227ber_free(struct ber *b)
1228{
1229	free(b->br_wbuf);
1230}
1231
1232static ssize_t
1233ber_getc(struct ber *b, u_char *c)
1234{
1235	ssize_t r;
1236	/*
1237	 * XXX calling read here is wrong in many ways. The most obvious one
1238	 * being that we will block till data arrives.
1239	 * But for now it is _good enough_ *gulp*
1240	 */
1241	if (b->fd == -1)
1242		r = ber_readbuf(b, c, 1);
1243	else
1244		r = read(b->fd, c, 1);
1245	return r;
1246}
1247
1248static ssize_t
1249ber_read(struct ber *ber, void *buf, size_t len)
1250{
1251	u_char *b = buf;
1252	ssize_t	r, remain = len;
1253
1254	/*
1255	 * XXX calling read here is wrong in many ways. The most obvious one
1256	 * being that we will block till data arrives.
1257	 * But for now it is _good enough_ *gulp*
1258	 */
1259
1260	while (remain > 0) {
1261		if (ber->fd == -1)
1262			r = ber_readbuf(ber, b, remain);
1263		else
1264			r = read(ber->fd, b, remain);
1265		if (r == -1) {
1266			if (errno == EINTR || errno == EAGAIN)
1267				continue;
1268			return -1;
1269		}
1270		if (r == 0)
1271			return (b - (u_char *)buf);
1272		b += r;
1273		remain -= r;
1274	}
1275	return (b - (u_char *)buf);
1276}
1277