1/*	$OpenBSD: ber.c,v 1.9 2015/02/12 00:30:38 pelikan Exp $ */
2
3/*
4 * Copyright (c) 2007 Reyk Floeter <reyk@vantronix.net>
5 * Copyright (c) 2006, 2007 Claudio Jeker <claudio@openbsd.org>
6 * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
7 *
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
11 *
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19 */
20
21#include <sys/types.h>
22
23#include <errno.h>
24#include <limits.h>
25#include <stdlib.h>
26#include <err.h>	/* XXX for debug output */
27#include <stdio.h>	/* XXX for debug output */
28#include <string.h>
29#include <unistd.h>
30#include <stdarg.h>
31
32#include "ber.h"
33
34#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
35
36#define BER_TYPE_CONSTRUCTED	0x20	/* otherwise primitive */
37#define BER_TYPE_SINGLE_MAX	30
38#define BER_TAG_MASK		0x1f
39#define BER_TAG_MORE		0x80	/* more subsequent octets */
40#define BER_TAG_TYPE_MASK	0x7f
41#define BER_CLASS_SHIFT		6
42
43static int	ber_dump_element(struct ber *ber, struct ber_element *root);
44static void	ber_dump_header(struct ber *ber, struct ber_element *root);
45static void	ber_putc(struct ber *ber, u_char c);
46static void	ber_write(struct ber *ber, void *buf, size_t len);
47static ssize_t	get_id(struct ber *b, unsigned long *tag, int *class,
48    int *cstruct);
49static ssize_t	get_len(struct ber *b, ssize_t *len);
50static ssize_t	ber_read_element(struct ber *ber, struct ber_element *elm);
51static ssize_t	ber_readbuf(struct ber *b, void *buf, size_t nbytes);
52static ssize_t	ber_getc(struct ber *b, u_char *c);
53static ssize_t	ber_read(struct ber *ber, void *buf, size_t len);
54
55#ifdef DEBUG
56#define DPRINTF(...)	printf(__VA_ARGS__)
57#else
58#define DPRINTF(...)	do { } while (0)
59#endif
60
61struct ber_element *
62ber_get_element(unsigned long encoding)
63{
64	struct ber_element *elm;
65
66	if ((elm = calloc(1, sizeof(*elm))) == NULL)
67		return NULL;
68
69	elm->be_encoding = encoding;
70	ber_set_header(elm, BER_CLASS_UNIVERSAL, BER_TYPE_DEFAULT);
71
72	return elm;
73}
74
75void
76ber_set_header(struct ber_element *elm, int class, unsigned long type)
77{
78	elm->be_class = class & BER_CLASS_MASK;
79	if (type == BER_TYPE_DEFAULT)
80		type = elm->be_encoding;
81	elm->be_type = type;
82}
83
84void
85ber_link_elements(struct ber_element *prev, struct ber_element *elm)
86{
87	if (prev != NULL) {
88		if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
89		    prev->be_encoding == BER_TYPE_SET) &&
90		    prev->be_sub == NULL)
91			prev->be_sub = elm;
92		else
93			prev->be_next = elm;
94	}
95}
96
97struct ber_element *
98ber_unlink_elements(struct ber_element *prev)
99{
100	struct ber_element *elm;
101
102	if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
103	    prev->be_encoding == BER_TYPE_SET) &&
104	    prev->be_sub != NULL) {
105		elm = prev->be_sub;
106		prev->be_sub = NULL;
107	} else {
108		elm = prev->be_next;
109		prev->be_next = NULL;
110	}
111
112	return (elm);
113}
114
115void
116ber_replace_elements(struct ber_element *prev, struct ber_element *new)
117{
118	struct ber_element *ber, *next;
119
120	ber = ber_unlink_elements(prev);
121	next = ber_unlink_elements(ber);
122	ber_link_elements(new, next);
123	ber_link_elements(prev, new);
124
125	/* cleanup old element */
126	ber_free_elements(ber);
127}
128
129struct ber_element *
130ber_add_sequence(struct ber_element *prev)
131{
132	struct ber_element *elm;
133
134	if ((elm = ber_get_element(BER_TYPE_SEQUENCE)) == NULL)
135		return NULL;
136
137	ber_link_elements(prev, elm);
138
139	return elm;
140}
141
142struct ber_element *
143ber_add_set(struct ber_element *prev)
144{
145	struct ber_element *elm;
146
147	if ((elm = ber_get_element(BER_TYPE_SET)) == NULL)
148		return NULL;
149
150	ber_link_elements(prev, elm);
151
152	return elm;
153}
154
155struct ber_element *
156ber_add_enumerated(struct ber_element *prev, long long val)
157{
158	struct ber_element *elm;
159	u_int i, len = 0;
160	u_char cur, last = 0;
161
162	if ((elm = ber_get_element(BER_TYPE_ENUMERATED)) == NULL)
163		return NULL;
164
165	elm->be_numeric = val;
166
167	for (i = 0; i < sizeof(long long); i++) {
168		cur = val & 0xff;
169		if (cur != 0 && cur != 0xff)
170			len = i;
171		if ((cur == 0 && last & 0x80) ||
172		    (cur == 0xff && (last & 0x80) == 0))
173			len = i;
174		val >>= 8;
175		last = cur;
176	}
177	elm->be_len = len + 1;
178
179	ber_link_elements(prev, elm);
180
181	return elm;
182}
183
184struct ber_element *
185ber_add_integer(struct ber_element *prev, long long val)
186{
187	struct ber_element *elm;
188	u_int i, len = 0;
189	u_char cur, last = 0;
190
191	if ((elm = ber_get_element(BER_TYPE_INTEGER)) == NULL)
192		return NULL;
193
194	elm->be_numeric = val;
195
196	for (i = 0; i < sizeof(long long); i++) {
197		cur = val & 0xff;
198		if (cur != 0 && cur != 0xff)
199			len = i;
200		if ((cur == 0 && last & 0x80) ||
201		    (cur == 0xff && (last & 0x80) == 0))
202			len = i;
203		val >>= 8;
204		last = cur;
205	}
206	elm->be_len = len + 1;
207
208	ber_link_elements(prev, elm);
209
210	return elm;
211}
212
213int
214ber_get_integer(struct ber_element *elm, long long *n)
215{
216	if (elm->be_encoding != BER_TYPE_INTEGER)
217		return -1;
218
219	*n = elm->be_numeric;
220	return 0;
221}
222
223int
224ber_get_enumerated(struct ber_element *elm, long long *n)
225{
226	if (elm->be_encoding != BER_TYPE_ENUMERATED)
227		return -1;
228
229	*n = elm->be_numeric;
230	return 0;
231}
232
233
234struct ber_element *
235ber_add_boolean(struct ber_element *prev, int bool)
236{
237	struct ber_element *elm;
238
239	if ((elm = ber_get_element(BER_TYPE_BOOLEAN)) == NULL)
240		return NULL;
241
242	elm->be_numeric = bool ? 0xff : 0;
243	elm->be_len = 1;
244
245	ber_link_elements(prev, elm);
246
247	return elm;
248}
249
250int
251ber_get_boolean(struct ber_element *elm, int *b)
252{
253	if (elm->be_encoding != BER_TYPE_BOOLEAN)
254		return -1;
255
256	*b = !(elm->be_numeric == 0);
257	return 0;
258}
259
260struct ber_element *
261ber_add_string(struct ber_element *prev, const char *string)
262{
263	return ber_add_nstring(prev, string, strlen(string));
264}
265
266struct ber_element *
267ber_add_nstring(struct ber_element *prev, const char *string0, size_t len)
268{
269	struct ber_element *elm;
270	char *string;
271
272	if ((string = calloc(1, len)) == NULL)
273		return NULL;
274	if ((elm = ber_get_element(BER_TYPE_OCTETSTRING)) == NULL) {
275		free(string);
276		return NULL;
277	}
278
279	bcopy(string0, string, len);
280	elm->be_val = string;
281	elm->be_len = len;
282	elm->be_free = 1;		/* free string on cleanup */
283
284	ber_link_elements(prev, elm);
285
286	return elm;
287}
288
289int
290ber_get_string(struct ber_element *elm, char **s)
291{
292	if (elm->be_encoding != BER_TYPE_OCTETSTRING)
293		return -1;
294
295	*s = elm->be_val;
296	return 0;
297}
298
299int
300ber_get_nstring(struct ber_element *elm, void **p, size_t *len)
301{
302	if (elm->be_encoding != BER_TYPE_OCTETSTRING)
303		return -1;
304
305	*p = elm->be_val;
306	*len = elm->be_len;
307	return 0;
308}
309
310struct ber_element *
311ber_add_bitstring(struct ber_element *prev, const void *v0, size_t len)
312{
313	struct ber_element *elm;
314	void *v;
315
316	if ((v = calloc(1, len)) == NULL)
317		return NULL;
318	if ((elm = ber_get_element(BER_TYPE_BITSTRING)) == NULL) {
319		free(v);
320		return NULL;
321	}
322
323	bcopy(v0, v, len);
324	elm->be_val = v;
325	elm->be_len = len;
326	elm->be_free = 1;		/* free string on cleanup */
327
328	ber_link_elements(prev, elm);
329
330	return elm;
331}
332
333int
334ber_get_bitstring(struct ber_element *elm, void **v, size_t *len)
335{
336	if (elm->be_encoding != BER_TYPE_BITSTRING)
337		return -1;
338
339	*v = elm->be_val;
340	*len = elm->be_len;
341	return 0;
342}
343
344struct ber_element *
345ber_add_null(struct ber_element *prev)
346{
347	struct ber_element *elm;
348
349	if ((elm = ber_get_element(BER_TYPE_NULL)) == NULL)
350		return NULL;
351
352	ber_link_elements(prev, elm);
353
354	return elm;
355}
356
357int
358ber_get_null(struct ber_element *elm)
359{
360	if (elm->be_encoding != BER_TYPE_NULL)
361		return -1;
362
363	return 0;
364}
365
366struct ber_element *
367ber_add_eoc(struct ber_element *prev)
368{
369	struct ber_element *elm;
370
371	if ((elm = ber_get_element(BER_TYPE_EOC)) == NULL)
372		return NULL;
373
374	ber_link_elements(prev, elm);
375
376	return elm;
377}
378
379int
380ber_get_eoc(struct ber_element *elm)
381{
382	if (elm->be_encoding != BER_TYPE_EOC)
383		return -1;
384
385	return 0;
386}
387
388size_t
389ber_oid2ber(struct ber_oid *o, u_int8_t *buf, size_t len)
390{
391	u_int32_t	 v;
392	u_int		 i, j = 0, k;
393
394	if (o->bo_n < BER_MIN_OID_LEN || o->bo_n > BER_MAX_OID_LEN ||
395	    o->bo_id[0] > 2 || o->bo_id[1] > 40)
396		return (0);
397
398	v = (o->bo_id[0] * 40) + o->bo_id[1];
399	for (i = 2, j = 0; i <= o->bo_n; v = o->bo_id[i], i++) {
400		for (k = 28; k >= 7; k -= 7) {
401			if (v >= (u_int)(1 << k)) {
402				if (len)
403					buf[j] = v >> k | BER_TAG_MORE;
404				j++;
405			}
406		}
407		if (len)
408			buf[j] = v & BER_TAG_TYPE_MASK;
409		j++;
410	}
411
412	return (j);
413}
414
415int
416ber_string2oid(const char *oidstr, struct ber_oid *o)
417{
418	char			*sp, *p, str[BUFSIZ];
419	const char		*errstr;
420
421	if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
422		return (-1);
423	bzero(o, sizeof(*o));
424
425	/* Parse OID strings in the common forms n.n.n, n_n_n_n, or n-n-n */
426	for (p = sp = str; p != NULL; sp = p) {
427		if ((p = strpbrk(p, "._-")) != NULL)
428			*p++ = '\0';
429		o->bo_id[o->bo_n++] = strtonum(sp, 0, UINT_MAX, &errstr);
430		if (errstr || o->bo_n > BER_MAX_OID_LEN)
431			return (-1);
432	}
433
434	return (0);
435}
436
437struct ber_element *
438ber_add_oid(struct ber_element *prev, struct ber_oid *o)
439{
440	struct ber_element	*elm;
441	u_int8_t		*buf;
442	size_t			 len;
443
444	if ((elm = ber_get_element(BER_TYPE_OBJECT)) == NULL)
445		return (NULL);
446
447	if ((len = ber_oid2ber(o, NULL, 0)) == 0)
448		goto fail;
449
450	if ((buf = calloc(1, len)) == NULL)
451		goto fail;
452
453	elm->be_val = buf;
454	elm->be_len = len;
455	elm->be_free = 1;
456
457	if (ber_oid2ber(o, buf, len) != len)
458		goto fail;
459
460	ber_link_elements(prev, elm);
461
462	return (elm);
463
464 fail:
465	ber_free_elements(elm);
466	return (NULL);
467}
468
469struct ber_element *
470ber_add_noid(struct ber_element *prev, struct ber_oid *o, int n)
471{
472	struct ber_oid		 no;
473
474	if (n > BER_MAX_OID_LEN)
475		return (NULL);
476	no.bo_n = n;
477	bcopy(&o->bo_id, &no.bo_id, sizeof(no.bo_id));
478
479	return (ber_add_oid(prev, &no));
480}
481
482struct ber_element *
483ber_add_oidstring(struct ber_element *prev, const char *oidstr)
484{
485	struct ber_oid		 o;
486
487	if (ber_string2oid(oidstr, &o) == -1)
488		return (NULL);
489
490	return (ber_add_oid(prev, &o));
491}
492
493int
494ber_get_oid(struct ber_element *elm, struct ber_oid *o)
495{
496	u_int8_t	*buf;
497	size_t		 len, i = 0, j = 0;
498
499	if (elm->be_encoding != BER_TYPE_OBJECT)
500		return (-1);
501
502	buf = elm->be_val;
503	len = elm->be_len;
504
505	if (!buf[i])
506		return (-1);
507
508	bzero(o, sizeof(*o));
509	o->bo_id[j++] = buf[i] / 40;
510	o->bo_id[j++] = buf[i++] % 40;
511	for (; i < len && j < BER_MAX_OID_LEN; i++) {
512		o->bo_id[j] = (o->bo_id[j] << 7) + (buf[i] & ~0x80);
513		if (buf[i] & 0x80)
514			continue;
515		j++;
516	}
517	o->bo_n = j;
518
519	return (0);
520}
521
522struct ber_element *
523ber_printf_elements(struct ber_element *ber, char *fmt, ...)
524{
525	va_list			 ap;
526	int			 d, class;
527	size_t			 len;
528	unsigned long		 type;
529	long long		 i;
530	char			*s;
531	void			*p;
532	struct ber_oid		*o;
533	struct ber_element	*sub = ber, *e;
534
535	va_start(ap, fmt);
536	while (*fmt) {
537		switch (*fmt++) {
538		case 'B':
539			p = va_arg(ap, void *);
540			len = va_arg(ap, size_t);
541			if ((ber = ber_add_bitstring(ber, p, len)) == NULL)
542				goto fail;
543			break;
544		case 'b':
545			d = va_arg(ap, int);
546			if ((ber = ber_add_boolean(ber, d)) == NULL)
547				goto fail;
548			break;
549		case 'd':
550			d = va_arg(ap, int);
551			if ((ber = ber_add_integer(ber, d)) == NULL)
552				goto fail;
553			break;
554		case 'e':
555			e = va_arg(ap, struct ber_element *);
556			ber_link_elements(ber, e);
557			break;
558		case 'E':
559			i = va_arg(ap, long long);
560			if ((ber = ber_add_enumerated(ber, i)) == NULL)
561				goto fail;
562			break;
563		case 'i':
564			i = va_arg(ap, long long);
565			if ((ber = ber_add_integer(ber, i)) == NULL)
566				goto fail;
567			break;
568		case 'O':
569			o = va_arg(ap, struct ber_oid *);
570			if ((ber = ber_add_oid(ber, o)) == NULL)
571				goto fail;
572			break;
573		case 'o':
574			s = va_arg(ap, char *);
575			if ((ber = ber_add_oidstring(ber, s)) == NULL)
576				goto fail;
577			break;
578		case 's':
579			s = va_arg(ap, char *);
580			if ((ber = ber_add_string(ber, s)) == NULL)
581				goto fail;
582			break;
583		case 't':
584			class = va_arg(ap, int);
585			type = va_arg(ap, unsigned long);
586			ber_set_header(ber, class, type);
587			break;
588		case 'x':
589			s = va_arg(ap, char *);
590			len = va_arg(ap, size_t);
591			if ((ber = ber_add_nstring(ber, s, len)) == NULL)
592				goto fail;
593			break;
594		case '0':
595			if ((ber = ber_add_null(ber)) == NULL)
596				goto fail;
597			break;
598		case '{':
599			if ((ber = sub = ber_add_sequence(ber)) == NULL)
600				goto fail;
601			break;
602		case '(':
603			if ((ber = sub = ber_add_set(ber)) == NULL)
604				goto fail;
605			break;
606		case '}':
607		case ')':
608			ber = sub;
609			break;
610		case '.':
611			if ((e = ber_add_eoc(ber)) == NULL)
612				goto fail;
613			ber = e;
614			break;
615		default:
616			break;
617		}
618	}
619	va_end(ap);
620
621	return (ber);
622 fail:
623	va_end(ap);
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