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