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