ber.c revision 299583
1/*	$OpenBSD: ber.c,v 1.9 2015/02/12 00:30:38 pelikan Exp $ */
2/*	$FreeBSD: head/usr.sbin/ypldap/ber.c 299583 2016-05-13 00:58:05Z truckman $ */
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	ber_free_elements(ber);
625	return (NULL);
626}
627
628int
629ber_scanf_elements(struct ber_element *ber, char *fmt, ...)
630{
631#define _MAX_SEQ		 128
632	va_list			 ap;
633	int			*d, level = -1;
634	unsigned long		*t;
635	long long		*i;
636	void			**ptr;
637	size_t			*len, ret = 0, n = strlen(fmt);
638	char			**s;
639	struct ber_oid		*o;
640	struct ber_element	*parent[_MAX_SEQ], **e;
641
642	bzero(parent, sizeof(struct ber_element *) * _MAX_SEQ);
643
644	va_start(ap, fmt);
645	while (*fmt) {
646		switch (*fmt++) {
647		case 'B':
648			ptr = va_arg(ap, void **);
649			len = va_arg(ap, size_t *);
650			if (ber_get_bitstring(ber, ptr, len) == -1)
651				goto fail;
652			ret++;
653			break;
654		case 'b':
655			d = va_arg(ap, int *);
656			if (ber_get_boolean(ber, d) == -1)
657				goto fail;
658			ret++;
659			break;
660		case 'e':
661			e = va_arg(ap, struct ber_element **);
662			*e = ber;
663			ret++;
664			continue;
665		case 'E':
666			i = va_arg(ap, long long *);
667			if (ber_get_enumerated(ber, i) == -1)
668				goto fail;
669			ret++;
670			break;
671		case 'i':
672			i = va_arg(ap, long long *);
673			if (ber_get_integer(ber, i) == -1)
674				goto fail;
675			ret++;
676			break;
677		case 'o':
678			o = va_arg(ap, struct ber_oid *);
679			if (ber_get_oid(ber, o) == -1)
680				goto fail;
681			ret++;
682			break;
683		case 'S':
684			ret++;
685			break;
686		case 's':
687			s = va_arg(ap, char **);
688			if (ber_get_string(ber, s) == -1)
689				goto fail;
690			ret++;
691			break;
692		case 't':
693			d = va_arg(ap, int *);
694			t = va_arg(ap, unsigned long *);
695			*d = ber->be_class;
696			*t = ber->be_type;
697			ret++;
698			continue;
699		case 'x':
700			ptr = va_arg(ap, void **);
701			len = va_arg(ap, size_t *);
702			if (ber_get_nstring(ber, ptr, len) == -1)
703				goto fail;
704			ret++;
705			break;
706		case '0':
707			if (ber->be_encoding != BER_TYPE_NULL)
708				goto fail;
709			ret++;
710			break;
711		case '.':
712			if (ber->be_encoding != BER_TYPE_EOC)
713				goto fail;
714			ret++;
715			break;
716		case '{':
717		case '(':
718			if (ber->be_encoding != BER_TYPE_SEQUENCE &&
719			    ber->be_encoding != BER_TYPE_SET)
720				goto fail;
721			if (ber->be_sub == NULL || level >= _MAX_SEQ-1)
722				goto fail;
723			parent[++level] = ber;
724			ber = ber->be_sub;
725			ret++;
726			continue;
727		case '}':
728		case ')':
729			if (level < 0 || parent[level] == NULL)
730				goto fail;
731			ber = parent[level--];
732			ret++;
733			continue;
734		default:
735			goto fail;
736		}
737
738		if (ber->be_next == NULL)
739			continue;
740		ber = ber->be_next;
741	}
742	va_end(ap);
743	return (ret == n ? 0 : -1);
744
745 fail:
746	va_end(ap);
747	return (-1);
748
749}
750
751/*
752 * write ber elements to the socket
753 *
754 * params:
755 *	ber	holds the socket
756 *	root	fully populated element tree
757 *
758 * returns:
759 *      >=0     number of bytes written
760 *	-1	on failure and sets errno
761 */
762int
763ber_write_elements(struct ber *ber, struct ber_element *root)
764{
765	size_t len;
766
767	/* calculate length because only the definite form is required */
768	len = ber_calc_len(root);
769	DPRINTF("write ber element of %zd bytes length\n", len);
770
771	if (ber->br_wbuf != NULL && ber->br_wbuf + len > ber->br_wend) {
772		free(ber->br_wbuf);
773		ber->br_wbuf = NULL;
774	}
775	if (ber->br_wbuf == NULL) {
776		if ((ber->br_wbuf = malloc(len)) == NULL)
777			return -1;
778		ber->br_wend = ber->br_wbuf + len;
779	}
780
781	/* reset write pointer */
782	ber->br_wptr = ber->br_wbuf;
783
784	if (ber_dump_element(ber, root) == -1)
785		return -1;
786
787	/* XXX this should be moved to a different function */
788	if (ber->fd != -1)
789		return write(ber->fd, ber->br_wbuf, len);
790
791	return (len);
792}
793
794/*
795 * read ber elements from the socket
796 *
797 * params:
798 *	ber	holds the socket and lot more
799 *	root	if NULL, build up an element tree from what we receive on
800 *		the wire. If not null, use the specified encoding for the
801 *		elements received.
802 *
803 * returns:
804 *	!=NULL, elements read and store in the ber_element tree
805 *	NULL, type mismatch or read error
806 */
807struct ber_element *
808ber_read_elements(struct ber *ber, struct ber_element *elm)
809{
810	struct ber_element *root = elm;
811
812	if (root == NULL) {
813		if ((root = ber_get_element(0)) == NULL)
814			return NULL;
815	}
816
817	DPRINTF("read ber elements, root %p\n", root);
818
819	if (ber_read_element(ber, root) == -1) {
820		/* Cleanup if root was allocated by us */
821		if (elm == NULL)
822			ber_free_elements(root);
823		return NULL;
824	}
825
826	return root;
827}
828
829void
830ber_free_elements(struct ber_element *root)
831{
832	if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
833	    root->be_encoding == BER_TYPE_SET))
834		ber_free_elements(root->be_sub);
835	if (root->be_next)
836		ber_free_elements(root->be_next);
837	if (root->be_free && (root->be_encoding == BER_TYPE_OCTETSTRING ||
838	    root->be_encoding == BER_TYPE_BITSTRING ||
839	    root->be_encoding == BER_TYPE_OBJECT))
840		free(root->be_val);
841	free(root);
842}
843
844size_t
845ber_calc_len(struct ber_element *root)
846{
847	unsigned long t;
848	size_t s;
849	size_t size = 2;	/* minimum 1 byte head and 1 byte size */
850
851	/* calculate the real length of a sequence or set */
852	if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
853	    root->be_encoding == BER_TYPE_SET))
854		root->be_len = ber_calc_len(root->be_sub);
855
856	/* fix header length for extended types */
857	if (root->be_type > BER_TYPE_SINGLE_MAX)
858		for (t = root->be_type; t > 0; t >>= 7)
859			size++;
860	if (root->be_len >= BER_TAG_MORE)
861		for (s = root->be_len; s > 0; s >>= 8)
862			size++;
863
864	/* calculate the length of the following elements */
865	if (root->be_next)
866		size += ber_calc_len(root->be_next);
867
868	/* This is an empty element, do not use a minimal size */
869	if (root->be_type == BER_TYPE_EOC && root->be_len == 0)
870		return (0);
871
872	return (root->be_len + size);
873}
874
875/*
876 * internal functions
877 */
878
879static int
880ber_dump_element(struct ber *ber, struct ber_element *root)
881{
882	unsigned long long l;
883	int i;
884	uint8_t u;
885
886	ber_dump_header(ber, root);
887
888	switch (root->be_encoding) {
889	case BER_TYPE_BOOLEAN:
890	case BER_TYPE_INTEGER:
891	case BER_TYPE_ENUMERATED:
892		l = (unsigned long long)root->be_numeric;
893		for (i = root->be_len; i > 0; i--) {
894			u = (l >> ((i - 1) * 8)) & 0xff;
895			ber_putc(ber, u);
896		}
897		break;
898	case BER_TYPE_BITSTRING:
899		return -1;
900	case BER_TYPE_OCTETSTRING:
901	case BER_TYPE_OBJECT:
902		ber_write(ber, root->be_val, root->be_len);
903		break;
904	case BER_TYPE_NULL:	/* no payload */
905	case BER_TYPE_EOC:
906		break;
907	case BER_TYPE_SEQUENCE:
908	case BER_TYPE_SET:
909		if (root->be_sub && ber_dump_element(ber, root->be_sub) == -1)
910			return -1;
911		break;
912	}
913
914	if (root->be_next == NULL)
915		return 0;
916	return ber_dump_element(ber, root->be_next);
917}
918
919static void
920ber_dump_header(struct ber *ber, struct ber_element *root)
921{
922	u_char	id = 0, t, buf[8];
923	unsigned long type;
924	size_t size;
925
926	/* class universal, type encoding depending on type value */
927	/* length encoding */
928	if (root->be_type <= BER_TYPE_SINGLE_MAX) {
929		id = root->be_type | (root->be_class << BER_CLASS_SHIFT);
930		if (root->be_encoding == BER_TYPE_SEQUENCE ||
931		    root->be_encoding == BER_TYPE_SET)
932			id |= BER_TYPE_CONSTRUCTED;
933
934		ber_putc(ber, id);
935	} else {
936		id = BER_TAG_MASK | (root->be_class << BER_CLASS_SHIFT);
937		if (root->be_encoding == BER_TYPE_SEQUENCE ||
938		    root->be_encoding == BER_TYPE_SET)
939			id |= BER_TYPE_CONSTRUCTED;
940
941		ber_putc(ber, id);
942
943		for (t = 0, type = root->be_type; type > 0; type >>= 7)
944			buf[t++] = type & ~BER_TAG_MORE;
945
946		while (t-- > 0) {
947			if (t > 0)
948				buf[t] |= BER_TAG_MORE;
949			ber_putc(ber, buf[t]);
950		}
951	}
952
953	if (root->be_len < BER_TAG_MORE) {
954		/* short form */
955		ber_putc(ber, root->be_len);
956	} else {
957		for (t = 0, size = root->be_len; size > 0; size >>= 8)
958			buf[t++] = size & 0xff;
959
960		ber_putc(ber, t | BER_TAG_MORE);
961
962		while (t > 0)
963			ber_putc(ber, buf[--t]);
964	}
965}
966
967static void
968ber_putc(struct ber *ber, u_char c)
969{
970	if (ber->br_wptr + 1 <= ber->br_wend)
971		*ber->br_wptr = c;
972	ber->br_wptr++;
973}
974
975static void
976ber_write(struct ber *ber, void *buf, size_t len)
977{
978	if (ber->br_wptr + len <= ber->br_wend)
979		bcopy(buf, ber->br_wptr, len);
980	ber->br_wptr += len;
981}
982
983/*
984 * extract a BER encoded tag. There are two types, a short and long form.
985 */
986static ssize_t
987get_id(struct ber *b, unsigned long *tag, int *class, int *cstruct)
988{
989	u_char u;
990	size_t i = 0;
991	unsigned long t = 0;
992
993	if (ber_getc(b, &u) == -1)
994		return -1;
995
996	*class = (u >> BER_CLASS_SHIFT) & BER_CLASS_MASK;
997	*cstruct = (u & BER_TYPE_CONSTRUCTED) == BER_TYPE_CONSTRUCTED;
998
999	if ((u & BER_TAG_MASK) != BER_TAG_MASK) {
1000		*tag = u & BER_TAG_MASK;
1001		return 1;
1002	}
1003
1004	do {
1005		if (ber_getc(b, &u) == -1)
1006			return -1;
1007		t = (t << 7) | (u & ~BER_TAG_MORE);
1008		i++;
1009	} while (u & BER_TAG_MORE);
1010
1011	if (i > sizeof(unsigned long)) {
1012		errno = ERANGE;
1013		return -1;
1014	}
1015
1016	*tag = t;
1017	return i + 1;
1018}
1019
1020/*
1021 * extract length of a ber object -- if length is unknown an error is returned.
1022 */
1023static ssize_t
1024get_len(struct ber *b, ssize_t *len)
1025{
1026	u_char	u, n;
1027	ssize_t	s, r;
1028
1029	if (ber_getc(b, &u) == -1)
1030		return -1;
1031	if ((u & BER_TAG_MORE) == 0) {
1032		/* short form */
1033		*len = u;
1034		return 1;
1035	}
1036
1037	n = u & ~BER_TAG_MORE;
1038	if (sizeof(ssize_t) < n) {
1039		errno = ERANGE;
1040		return -1;
1041	}
1042	r = n + 1;
1043
1044	for (s = 0; n > 0; n--) {
1045		if (ber_getc(b, &u) == -1)
1046			return -1;
1047		s = (s << 8) | u;
1048	}
1049
1050	if (s < 0) {
1051		/* overflow */
1052		errno = ERANGE;
1053		return -1;
1054	}
1055
1056	if (s == 0) {
1057		/* invalid encoding */
1058		errno = EINVAL;
1059		return -1;
1060	}
1061
1062	*len = s;
1063	return r;
1064}
1065
1066static ssize_t
1067ber_read_element(struct ber *ber, struct ber_element *elm)
1068{
1069	long long val = 0;
1070	struct ber_element *next;
1071	unsigned long type;
1072	int i, class, cstruct;
1073	ssize_t len, r, totlen = 0;
1074	u_char c;
1075
1076	if ((r = get_id(ber, &type, &class, &cstruct)) == -1)
1077		return -1;
1078	DPRINTF("ber read got class %d type %lu, %s\n",
1079	    class, type, cstruct ? "constructive" : "primitive");
1080	totlen += r;
1081	if ((r = get_len(ber, &len)) == -1)
1082		return -1;
1083	DPRINTF("ber read element size %zd\n", len);
1084	totlen += r + len;
1085
1086	/*
1087	 * If using an external buffer and the total size of the element
1088	 * is larger, then the external buffer don't bother to continue.
1089	 */
1090	if (ber->fd == -1 && len > ber->br_rend - ber->br_rptr) {
1091		errno = ECANCELED;
1092		return -1;
1093	}
1094
1095	elm->be_type = type;
1096	elm->be_len = len;
1097	elm->be_class = class;
1098
1099	if (elm->be_encoding == 0) {
1100		/* try to figure out the encoding via class, type and cstruct */
1101		if (cstruct)
1102			elm->be_encoding = BER_TYPE_SEQUENCE;
1103		else if (class == BER_CLASS_UNIVERSAL)
1104			elm->be_encoding = type;
1105		else if (ber->br_application != NULL) {
1106			/*
1107			 * Ask the application to map the encoding to a
1108			 * universal type. For example, a SMI IpAddress
1109			 * type is defined as 4 byte OCTET STRING.
1110			 */
1111			elm->be_encoding = (*ber->br_application)(elm);
1112		} else
1113			/* last resort option */
1114			elm->be_encoding = BER_TYPE_NULL;
1115	}
1116
1117	switch (elm->be_encoding) {
1118	case BER_TYPE_EOC:	/* End-Of-Content */
1119		break;
1120	case BER_TYPE_BOOLEAN:
1121	case BER_TYPE_INTEGER:
1122	case BER_TYPE_ENUMERATED:
1123		if (len > (ssize_t)sizeof(long long))
1124			return -1;
1125		for (i = 0; i < len; i++) {
1126			if (ber_getc(ber, &c) != 1)
1127				return -1;
1128			val <<= 8;
1129			val |= c;
1130		}
1131
1132		/* sign extend if MSB is set */
1133		if (val >> ((i - 1) * 8) & 0x80)
1134			val |= ULLONG_MAX << (i * 8);
1135		elm->be_numeric = val;
1136		break;
1137	case BER_TYPE_BITSTRING:
1138		elm->be_val = malloc(len);
1139		if (elm->be_val == NULL)
1140			return -1;
1141		elm->be_free = 1;
1142		elm->be_len = len;
1143		ber_read(ber, elm->be_val, len);
1144		break;
1145	case BER_TYPE_OCTETSTRING:
1146	case BER_TYPE_OBJECT:
1147		elm->be_val = malloc(len + 1);
1148		if (elm->be_val == NULL)
1149			return -1;
1150		elm->be_free = 1;
1151		elm->be_len = len;
1152		ber_read(ber, elm->be_val, len);
1153		((u_char *)elm->be_val)[len] = '\0';
1154		break;
1155	case BER_TYPE_NULL:	/* no payload */
1156		if (len != 0)
1157			return -1;
1158		break;
1159	case BER_TYPE_SEQUENCE:
1160	case BER_TYPE_SET:
1161		if (elm->be_sub == NULL) {
1162			if ((elm->be_sub = ber_get_element(0)) == NULL)
1163				return -1;
1164		}
1165		next = elm->be_sub;
1166		while (len > 0) {
1167			r = ber_read_element(ber, next);
1168			if (r == -1)
1169				return -1;
1170			len -= r;
1171			if (len > 0 && next->be_next == NULL) {
1172				if ((next->be_next = ber_get_element(0)) ==
1173				    NULL)
1174					return -1;
1175			}
1176			next = next->be_next;
1177		}
1178		break;
1179	}
1180	return totlen;
1181}
1182
1183static ssize_t
1184ber_readbuf(struct ber *b, void *buf, size_t nbytes)
1185{
1186	size_t	 sz;
1187	size_t	 len;
1188
1189	if (b->br_rbuf == NULL)
1190		return -1;
1191
1192	sz = b->br_rend - b->br_rptr;
1193	len = MINIMUM(nbytes, sz);
1194	if (len == 0) {
1195		errno = ECANCELED;
1196		return (-1);	/* end of buffer and parser wants more data */
1197	}
1198
1199	bcopy(b->br_rptr, buf, len);
1200	b->br_rptr += len;
1201
1202	return (len);
1203}
1204
1205void
1206ber_set_readbuf(struct ber *b, void *buf, size_t len)
1207{
1208	b->br_rbuf = b->br_rptr = buf;
1209	b->br_rend = (u_int8_t *)buf + len;
1210}
1211
1212ssize_t
1213ber_get_writebuf(struct ber *b, void **buf)
1214{
1215	if (b->br_wbuf == NULL)
1216		return -1;
1217	*buf = b->br_wbuf;
1218	return (b->br_wend - b->br_wbuf);
1219}
1220
1221void
1222ber_set_application(struct ber *b, unsigned long (*cb)(struct ber_element *))
1223{
1224	b->br_application = cb;
1225}
1226
1227void
1228ber_free(struct ber *b)
1229{
1230	free(b->br_wbuf);
1231}
1232
1233static ssize_t
1234ber_getc(struct ber *b, u_char *c)
1235{
1236	ssize_t r;
1237	/*
1238	 * XXX calling read here is wrong in many ways. The most obvious one
1239	 * being that we will block till data arrives.
1240	 * But for now it is _good enough_ *gulp*
1241	 */
1242	if (b->fd == -1)
1243		r = ber_readbuf(b, c, 1);
1244	else
1245		r = read(b->fd, c, 1);
1246	return r;
1247}
1248
1249static ssize_t
1250ber_read(struct ber *ber, void *buf, size_t len)
1251{
1252	u_char *b = buf;
1253	ssize_t	r, remain = len;
1254
1255	/*
1256	 * XXX calling read here is wrong in many ways. The most obvious one
1257	 * being that we will block till data arrives.
1258	 * But for now it is _good enough_ *gulp*
1259	 */
1260
1261	while (remain > 0) {
1262		if (ber->fd == -1)
1263			r = ber_readbuf(ber, b, remain);
1264		else
1265			r = read(ber->fd, b, remain);
1266		if (r == -1) {
1267			if (errno == EINTR || errno == EAGAIN)
1268				continue;
1269			return -1;
1270		}
1271		if (r == 0)
1272			return (b - (u_char *)buf);
1273		b += r;
1274		remain -= r;
1275	}
1276	return (b - (u_char *)buf);
1277}
1278