xref: /openbsd/lib/libutil/ber.c (revision 771fbea0)
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 
41 static int	ober_dump_element(struct ber *ber, struct ber_element *root);
42 static void	ober_dump_header(struct ber *ber, struct ber_element *root);
43 static void	ober_putc(struct ber *ber, u_char c);
44 static void	ober_write(struct ber *ber, void *buf, size_t len);
45 static ssize_t	get_id(struct ber *b, unsigned int *tag, int *class,
46     int *cstruct);
47 static ssize_t	get_len(struct ber *b, ssize_t *len);
48 static ssize_t	ober_read_element(struct ber *ber, struct ber_element *elm);
49 static ssize_t	ober_getc(struct ber *b, u_char *c);
50 static 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 
58 struct ber_element *
59 ober_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 
72 void
73 ober_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 
81 void
82 ober_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 
94 struct ber_element *
95 ober_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 
112 void
113 ober_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 
126 struct ber_element *
127 ober_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 
139 struct ber_element *
140 ober_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 
152 struct ber_element *
153 ober_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 
181 struct ber_element *
182 ober_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 
210 int
211 ober_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 
221 int
222 ober_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 
232 struct ber_element *
233 ober_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 
248 int
249 ober_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 
259 struct ber_element *
260 ober_add_string(struct ber_element *prev, const char *string)
261 {
262 	return ober_add_nstring(prev, string, strlen(string));
263 }
264 
265 struct ber_element *
266 ober_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 
288 struct ber_element *
289 ober_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 
294 int
295 ober_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 
310 int
311 ober_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 
327 int
328 ober_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 
340 struct ber_element *
341 ober_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 
363 int
364 ober_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 
380 struct ber_element *
381 ober_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 
393 int
394 ober_get_null(struct ber_element *elm)
395 {
396 	if (elm->be_encoding != BER_TYPE_NULL)
397 		return -1;
398 
399 	return 0;
400 }
401 
402 struct ber_element *
403 ober_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 
415 int
416 ober_get_eoc(struct ber_element *elm)
417 {
418 	if (elm->be_encoding != BER_TYPE_EOC)
419 		return -1;
420 
421 	return 0;
422 }
423 
424 size_t
425 ober_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 
451 int
452 ober_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 
473 int
474 ober_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 
499 struct ber_element *
500 ober_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 
531 struct ber_element *
532 ober_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 
544 struct ber_element *
545 ober_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 
555 int
556 ober_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 
584 struct ber_element *
585 ober_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 
689 int
690 ober_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 
833 ssize_t
834 ober_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  */
853 ssize_t
854 ober_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 
881 void
882 ober_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  */
901 struct ber_element *
902 ober_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 
923 off_t
924 ober_getpos(struct ber_element *elm)
925 {
926 	return elm->be_offs;
927 }
928 
929 void
930 ober_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 
942 void
943 ober_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 
959 size_t
960 ober_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 
991 void
992 ober_set_application(struct ber *b, unsigned int (*cb)(struct ber_element *))
993 {
994 	b->br_application = cb;
995 }
996 
997 void
998 ober_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 
1005 void
1006 ober_free(struct ber *b)
1007 {
1008 	free(b->br_wbuf);
1009 }
1010 
1011 /*
1012  * internal functions
1013  */
1014 
1015 static int
1016 ober_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 
1056 static void
1057 ober_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 
1104 static void
1105 ober_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 
1112 static void
1113 ober_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  */
1123 static ssize_t
1124 get_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  */
1166 static ssize_t
1167 get_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 
1218 static ssize_t
1219 ober_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 
1377 static ssize_t
1378 ober_getc(struct ber *b, u_char *c)
1379 {
1380 	return ober_read(b, c, 1);
1381 }
1382 
1383 static ssize_t
1384 ober_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