xref: /openbsd-src/lib/libutil/ber.c (revision 40632feda6a4f5d674c1e0d0ee088fd00fbf89b5)
1*40632fedSmartijn /*	$OpenBSD: ber.c,v 1.26 2023/11/10 12:12:02 martijn Exp $ */
2d4b95dc4Srob 
3d4b95dc4Srob /*
4d4b95dc4Srob  * Copyright (c) 2007, 2012 Reyk Floeter <reyk@openbsd.org>
5d4b95dc4Srob  * Copyright (c) 2006, 2007 Claudio Jeker <claudio@openbsd.org>
6d4b95dc4Srob  * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
7d4b95dc4Srob  *
8d4b95dc4Srob  * Permission to use, copy, modify, and distribute this software for any
9d4b95dc4Srob  * purpose with or without fee is hereby granted, provided that the above
10d4b95dc4Srob  * copyright notice and this permission notice appear in all copies.
11d4b95dc4Srob  *
12d4b95dc4Srob  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13d4b95dc4Srob  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14d4b95dc4Srob  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15d4b95dc4Srob  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16d4b95dc4Srob  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17d4b95dc4Srob  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18d4b95dc4Srob  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19d4b95dc4Srob  */
20d4b95dc4Srob 
21d4b95dc4Srob #include <sys/types.h>
22d4b95dc4Srob 
23d4b95dc4Srob #include <errno.h>
24d4b95dc4Srob #include <limits.h>
25d4b95dc4Srob #include <stdlib.h>
26d4b95dc4Srob #include <err.h>	/* XXX for debug output */
27d4b95dc4Srob #include <stdio.h>	/* XXX for debug output */
28d4b95dc4Srob #include <string.h>
29d4b95dc4Srob #include <unistd.h>
30d4b95dc4Srob #include <stdarg.h>
31d4b95dc4Srob 
32d4b95dc4Srob #include "ber.h"
33d4b95dc4Srob 
34d4b95dc4Srob #define BER_TYPE_CONSTRUCTED	0x20	/* otherwise primitive */
35d4b95dc4Srob #define BER_TYPE_SINGLE_MAX	30
36d4b95dc4Srob #define BER_TAG_MASK		0x1f
37d4b95dc4Srob #define BER_TAG_MORE		0x80	/* more subsequent octets */
38d4b95dc4Srob #define BER_TAG_TYPE_MASK	0x7f
39d4b95dc4Srob #define BER_CLASS_SHIFT		6
40d4b95dc4Srob 
41696b5899Stb static int	ober_dump_element(struct ber *ber, struct ber_element *root);
42696b5899Stb static void	ober_dump_header(struct ber *ber, struct ber_element *root);
43696b5899Stb static void	ober_putc(struct ber *ber, u_char c);
44696b5899Stb static void	ober_write(struct ber *ber, void *buf, size_t len);
45d4b95dc4Srob static ssize_t	get_id(struct ber *b, unsigned int *tag, int *class,
46d4b95dc4Srob     int *cstruct);
47d4b95dc4Srob static ssize_t	get_len(struct ber *b, ssize_t *len);
48696b5899Stb static ssize_t	ober_read_element(struct ber *ber, struct ber_element *elm);
49696b5899Stb static ssize_t	ober_getc(struct ber *b, u_char *c);
50696b5899Stb static ssize_t	ober_read(struct ber *ber, void *buf, size_t len);
51d4b95dc4Srob 
52d4b95dc4Srob #ifdef DEBUG
53d4b95dc4Srob #define DPRINTF(...)	printf(__VA_ARGS__)
54d4b95dc4Srob #else
55d4b95dc4Srob #define DPRINTF(...)	do { } while (0)
56d4b95dc4Srob #endif
57d4b95dc4Srob 
58d4b95dc4Srob struct ber_element *
ober_get_element(unsigned int encoding)59696b5899Stb ober_get_element(unsigned int encoding)
60d4b95dc4Srob {
61d4b95dc4Srob 	struct ber_element *elm;
62d4b95dc4Srob 
63d4b95dc4Srob 	if ((elm = calloc(1, sizeof(*elm))) == NULL)
64d4b95dc4Srob 		return NULL;
65d4b95dc4Srob 
66d4b95dc4Srob 	elm->be_encoding = encoding;
67696b5899Stb 	ober_set_header(elm, BER_CLASS_UNIVERSAL, BER_TYPE_DEFAULT);
68d4b95dc4Srob 
69d4b95dc4Srob 	return elm;
70d4b95dc4Srob }
71d4b95dc4Srob 
72d4b95dc4Srob void
ober_set_header(struct ber_element * elm,int class,unsigned int type)73696b5899Stb ober_set_header(struct ber_element *elm, int class, unsigned int type)
74d4b95dc4Srob {
75d4b95dc4Srob 	elm->be_class = class & BER_CLASS_MASK;
76d4b95dc4Srob 	if (type == BER_TYPE_DEFAULT)
77d4b95dc4Srob 		type = elm->be_encoding;
78d4b95dc4Srob 	elm->be_type = type;
79d4b95dc4Srob }
80d4b95dc4Srob 
81d4b95dc4Srob void
ober_link_elements(struct ber_element * prev,struct ber_element * elm)82696b5899Stb ober_link_elements(struct ber_element *prev, struct ber_element *elm)
83d4b95dc4Srob {
84d4b95dc4Srob 	if (prev != NULL) {
85d4b95dc4Srob 		if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
86d4b95dc4Srob 		    prev->be_encoding == BER_TYPE_SET) &&
87d4b95dc4Srob 		    prev->be_sub == NULL)
88d4b95dc4Srob 			prev->be_sub = elm;
89d4b95dc4Srob 		else
90d4b95dc4Srob 			prev->be_next = elm;
91d4b95dc4Srob 	}
92d4b95dc4Srob }
93d4b95dc4Srob 
94d4b95dc4Srob struct ber_element *
ober_unlink_elements(struct ber_element * prev)95696b5899Stb ober_unlink_elements(struct ber_element *prev)
96d4b95dc4Srob {
97d4b95dc4Srob 	struct ber_element *elm;
98d4b95dc4Srob 
99d4b95dc4Srob 	if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
100d4b95dc4Srob 	    prev->be_encoding == BER_TYPE_SET) &&
101d4b95dc4Srob 	    prev->be_sub != NULL) {
102d4b95dc4Srob 		elm = prev->be_sub;
103d4b95dc4Srob 		prev->be_sub = NULL;
104d4b95dc4Srob 	} else {
105d4b95dc4Srob 		elm = prev->be_next;
106d4b95dc4Srob 		prev->be_next = NULL;
107d4b95dc4Srob 	}
108d4b95dc4Srob 
109d4b95dc4Srob 	return (elm);
110d4b95dc4Srob }
111d4b95dc4Srob 
112d4b95dc4Srob void
ober_replace_elements(struct ber_element * prev,struct ber_element * new)113696b5899Stb ober_replace_elements(struct ber_element *prev, struct ber_element *new)
114d4b95dc4Srob {
115d4b95dc4Srob 	struct ber_element *ber, *next;
116d4b95dc4Srob 
117696b5899Stb 	ber = ober_unlink_elements(prev);
118696b5899Stb 	next = ober_unlink_elements(ber);
119696b5899Stb 	ober_link_elements(new, next);
120696b5899Stb 	ober_link_elements(prev, new);
121d4b95dc4Srob 
122d4b95dc4Srob 	/* cleanup old element */
123696b5899Stb 	ober_free_elements(ber);
124d4b95dc4Srob }
125d4b95dc4Srob 
126d4b95dc4Srob struct ber_element *
ober_add_sequence(struct ber_element * prev)127696b5899Stb ober_add_sequence(struct ber_element *prev)
128d4b95dc4Srob {
129d4b95dc4Srob 	struct ber_element *elm;
130d4b95dc4Srob 
131696b5899Stb 	if ((elm = ober_get_element(BER_TYPE_SEQUENCE)) == NULL)
132d4b95dc4Srob 		return NULL;
133d4b95dc4Srob 
134696b5899Stb 	ober_link_elements(prev, elm);
135d4b95dc4Srob 
136d4b95dc4Srob 	return elm;
137d4b95dc4Srob }
138d4b95dc4Srob 
139d4b95dc4Srob struct ber_element *
ober_add_set(struct ber_element * prev)140696b5899Stb ober_add_set(struct ber_element *prev)
141d4b95dc4Srob {
142d4b95dc4Srob 	struct ber_element *elm;
143d4b95dc4Srob 
144696b5899Stb 	if ((elm = ober_get_element(BER_TYPE_SET)) == NULL)
145d4b95dc4Srob 		return NULL;
146d4b95dc4Srob 
147696b5899Stb 	ober_link_elements(prev, elm);
148d4b95dc4Srob 
149d4b95dc4Srob 	return elm;
150d4b95dc4Srob }
151d4b95dc4Srob 
152d4b95dc4Srob struct ber_element *
ober_add_enumerated(struct ber_element * prev,long long val)153696b5899Stb ober_add_enumerated(struct ber_element *prev, long long val)
154d4b95dc4Srob {
155d4b95dc4Srob 	struct ber_element *elm;
156d4b95dc4Srob 	u_int i, len = 0;
157d4b95dc4Srob 	u_char cur, last = 0;
158d4b95dc4Srob 
159696b5899Stb 	if ((elm = ober_get_element(BER_TYPE_ENUMERATED)) == NULL)
160d4b95dc4Srob 		return NULL;
161d4b95dc4Srob 
162d4b95dc4Srob 	elm->be_numeric = val;
163d4b95dc4Srob 
164d4b95dc4Srob 	for (i = 0; i < sizeof(long long); i++) {
165d4b95dc4Srob 		cur = val & 0xff;
166d4b95dc4Srob 		if (cur != 0 && cur != 0xff)
167d4b95dc4Srob 			len = i;
168d4b95dc4Srob 		if ((cur == 0 && last & 0x80) ||
169d4b95dc4Srob 		    (cur == 0xff && (last & 0x80) == 0))
170d4b95dc4Srob 			len = i;
171d4b95dc4Srob 		val >>= 8;
172d4b95dc4Srob 		last = cur;
173d4b95dc4Srob 	}
174d4b95dc4Srob 	elm->be_len = len + 1;
175d4b95dc4Srob 
176696b5899Stb 	ober_link_elements(prev, elm);
177d4b95dc4Srob 
178d4b95dc4Srob 	return elm;
179d4b95dc4Srob }
180d4b95dc4Srob 
181d4b95dc4Srob struct ber_element *
ober_add_integer(struct ber_element * prev,long long val)182696b5899Stb ober_add_integer(struct ber_element *prev, long long val)
183d4b95dc4Srob {
184d4b95dc4Srob 	struct ber_element *elm;
185d4b95dc4Srob 	u_int i, len = 0;
186d4b95dc4Srob 	u_char cur, last = 0;
187d4b95dc4Srob 
188696b5899Stb 	if ((elm = ober_get_element(BER_TYPE_INTEGER)) == NULL)
189d4b95dc4Srob 		return NULL;
190d4b95dc4Srob 
191d4b95dc4Srob 	elm->be_numeric = val;
192d4b95dc4Srob 
193d4b95dc4Srob 	for (i = 0; i < sizeof(long long); i++) {
194d4b95dc4Srob 		cur = val & 0xff;
195d4b95dc4Srob 		if (cur != 0 && cur != 0xff)
196d4b95dc4Srob 			len = i;
197d4b95dc4Srob 		if ((cur == 0 && last & 0x80) ||
198d4b95dc4Srob 		    (cur == 0xff && (last & 0x80) == 0))
199d4b95dc4Srob 			len = i;
200d4b95dc4Srob 		val >>= 8;
201d4b95dc4Srob 		last = cur;
202d4b95dc4Srob 	}
203d4b95dc4Srob 	elm->be_len = len + 1;
204d4b95dc4Srob 
205696b5899Stb 	ober_link_elements(prev, elm);
206d4b95dc4Srob 
207d4b95dc4Srob 	return elm;
208d4b95dc4Srob }
209d4b95dc4Srob 
210d4b95dc4Srob int
ober_get_integer(struct ber_element * elm,long long * n)211696b5899Stb ober_get_integer(struct ber_element *elm, long long *n)
212d4b95dc4Srob {
213d4b95dc4Srob 	if (elm->be_encoding != BER_TYPE_INTEGER)
214d4b95dc4Srob 		return -1;
215d4b95dc4Srob 
216561e0011Smartijn 	if (n != NULL)
217d4b95dc4Srob 		*n = elm->be_numeric;
218d4b95dc4Srob 	return 0;
219d4b95dc4Srob }
220d4b95dc4Srob 
221d4b95dc4Srob int
ober_get_enumerated(struct ber_element * elm,long long * n)222696b5899Stb ober_get_enumerated(struct ber_element *elm, long long *n)
223d4b95dc4Srob {
224d4b95dc4Srob 	if (elm->be_encoding != BER_TYPE_ENUMERATED)
225d4b95dc4Srob 		return -1;
226d4b95dc4Srob 
227561e0011Smartijn 	if (n != NULL)
228d4b95dc4Srob 		*n = elm->be_numeric;
229d4b95dc4Srob 	return 0;
230d4b95dc4Srob }
231d4b95dc4Srob 
232d4b95dc4Srob struct ber_element *
ober_add_boolean(struct ber_element * prev,int bool)233696b5899Stb ober_add_boolean(struct ber_element *prev, int bool)
234d4b95dc4Srob {
235d4b95dc4Srob 	struct ber_element *elm;
236d4b95dc4Srob 
237696b5899Stb 	if ((elm = ober_get_element(BER_TYPE_BOOLEAN)) == NULL)
238d4b95dc4Srob 		return NULL;
239d4b95dc4Srob 
240d4b95dc4Srob 	elm->be_numeric = bool ? 0xff : 0;
241d4b95dc4Srob 	elm->be_len = 1;
242d4b95dc4Srob 
243696b5899Stb 	ober_link_elements(prev, elm);
244d4b95dc4Srob 
245d4b95dc4Srob 	return elm;
246d4b95dc4Srob }
247d4b95dc4Srob 
248d4b95dc4Srob int
ober_get_boolean(struct ber_element * elm,int * b)249696b5899Stb ober_get_boolean(struct ber_element *elm, int *b)
250d4b95dc4Srob {
251d4b95dc4Srob 	if (elm->be_encoding != BER_TYPE_BOOLEAN)
252d4b95dc4Srob 		return -1;
253d4b95dc4Srob 
254561e0011Smartijn 	if (b != NULL)
255d4b95dc4Srob 		*b = !(elm->be_numeric == 0);
256d4b95dc4Srob 	return 0;
257d4b95dc4Srob }
258d4b95dc4Srob 
259d4b95dc4Srob struct ber_element *
ober_add_string(struct ber_element * prev,const char * string)260696b5899Stb ober_add_string(struct ber_element *prev, const char *string)
261d4b95dc4Srob {
262696b5899Stb 	return ober_add_nstring(prev, string, strlen(string));
263d4b95dc4Srob }
264d4b95dc4Srob 
265d4b95dc4Srob struct ber_element *
ober_add_nstring(struct ber_element * prev,const char * string0,size_t len)266696b5899Stb ober_add_nstring(struct ber_element *prev, const char *string0, size_t len)
267d4b95dc4Srob {
268d4b95dc4Srob 	struct ber_element *elm;
269d4b95dc4Srob 	char *string;
270d4b95dc4Srob 
271d4b95dc4Srob 	if ((string = calloc(1, len + 1)) == NULL)
272d4b95dc4Srob 		return NULL;
273696b5899Stb 	if ((elm = ober_get_element(BER_TYPE_OCTETSTRING)) == NULL) {
274d4b95dc4Srob 		free(string);
275d4b95dc4Srob 		return NULL;
276d4b95dc4Srob 	}
277d4b95dc4Srob 
278d4b95dc4Srob 	bcopy(string0, string, len);
279d4b95dc4Srob 	elm->be_val = string;
280d4b95dc4Srob 	elm->be_len = len;
281d4b95dc4Srob 	elm->be_free = 1;		/* free string on cleanup */
282d4b95dc4Srob 
283696b5899Stb 	ober_link_elements(prev, elm);
284d4b95dc4Srob 
285d4b95dc4Srob 	return elm;
286d4b95dc4Srob }
287d4b95dc4Srob 
288d4b95dc4Srob struct ber_element *
ober_add_ostring(struct ber_element * prev,struct ber_octetstring * s)289696b5899Stb ober_add_ostring(struct ber_element *prev, struct ber_octetstring *s)
290d4b95dc4Srob {
291696b5899Stb 	return ober_add_nstring(prev, s->ostr_val, s->ostr_len);
292d4b95dc4Srob }
293d4b95dc4Srob 
294d4b95dc4Srob int
ober_get_string(struct ber_element * elm,char ** s)295696b5899Stb ober_get_string(struct ber_element *elm, char **s)
296d4b95dc4Srob {
297d4b95dc4Srob 	if (elm->be_encoding != BER_TYPE_OCTETSTRING)
298d4b95dc4Srob 		return -1;
299ff8cfb38Srob 	/* XXX some components use getstring on binary data containing \0 */
300d4b95dc4Srob #if 0
301d4b95dc4Srob 	if (memchr(elm->be_val, '\0', elm->be_len) != NULL)
302d4b95dc4Srob 		return -1;
303d4b95dc4Srob #endif
304d4b95dc4Srob 
305561e0011Smartijn 	if (s != NULL)
306d4b95dc4Srob 		*s = elm->be_val;
307d4b95dc4Srob 	return 0;
308d4b95dc4Srob }
309d4b95dc4Srob 
310d4b95dc4Srob int
ober_get_nstring(struct ber_element * elm,void ** p,size_t * len)311696b5899Stb ober_get_nstring(struct ber_element *elm, void **p, size_t *len)
312d4b95dc4Srob {
313d4b95dc4Srob 	if (elm->be_encoding != BER_TYPE_OCTETSTRING)
314d4b95dc4Srob 		return -1;
315d4b95dc4Srob 
316561e0011Smartijn 	if (len != NULL)
317d4b95dc4Srob 		*len = elm->be_len;
318561e0011Smartijn 	if (p != NULL) {
319561e0011Smartijn 		if (len != NULL)
320561e0011Smartijn 			*p = elm->be_val;
321561e0011Smartijn 		else
322561e0011Smartijn 			*p = NULL;
323561e0011Smartijn 	}
324d4b95dc4Srob 	return 0;
325d4b95dc4Srob }
326d4b95dc4Srob 
327d4b95dc4Srob int
ober_get_ostring(struct ber_element * elm,struct ber_octetstring * s)328696b5899Stb ober_get_ostring(struct ber_element *elm, struct ber_octetstring *s)
329d4b95dc4Srob {
330d4b95dc4Srob 	if (elm->be_encoding != BER_TYPE_OCTETSTRING)
331d4b95dc4Srob 		return -1;
332d4b95dc4Srob 
333561e0011Smartijn 	if (s != NULL) {
334d4b95dc4Srob 		s->ostr_val = elm->be_val;
335d4b95dc4Srob 		s->ostr_len = elm->be_len;
336561e0011Smartijn 	}
337d4b95dc4Srob 	return 0;
338d4b95dc4Srob }
339d4b95dc4Srob 
340d4b95dc4Srob struct ber_element *
ober_add_bitstring(struct ber_element * prev,const void * v0,size_t len)341696b5899Stb ober_add_bitstring(struct ber_element *prev, const void *v0, size_t len)
342d4b95dc4Srob {
343d4b95dc4Srob 	struct ber_element *elm;
344d4b95dc4Srob 	void *v;
345d4b95dc4Srob 
346d4b95dc4Srob 	if ((v = calloc(1, len)) == NULL)
347d4b95dc4Srob 		return NULL;
348696b5899Stb 	if ((elm = ober_get_element(BER_TYPE_BITSTRING)) == NULL) {
349d4b95dc4Srob 		free(v);
350d4b95dc4Srob 		return NULL;
351d4b95dc4Srob 	}
352d4b95dc4Srob 
353d4b95dc4Srob 	bcopy(v0, v, len);
354d4b95dc4Srob 	elm->be_val = v;
355d4b95dc4Srob 	elm->be_len = len;
356d4b95dc4Srob 	elm->be_free = 1;		/* free string on cleanup */
357d4b95dc4Srob 
358696b5899Stb 	ober_link_elements(prev, elm);
359d4b95dc4Srob 
360d4b95dc4Srob 	return elm;
361d4b95dc4Srob }
362d4b95dc4Srob 
363d4b95dc4Srob int
ober_get_bitstring(struct ber_element * elm,void ** v,size_t * len)364696b5899Stb ober_get_bitstring(struct ber_element *elm, void **v, size_t *len)
365d4b95dc4Srob {
366d4b95dc4Srob 	if (elm->be_encoding != BER_TYPE_BITSTRING)
367d4b95dc4Srob 		return -1;
368d4b95dc4Srob 
369561e0011Smartijn 	if (len != NULL)
370d4b95dc4Srob 		*len = elm->be_len;
371561e0011Smartijn 	if (v != NULL) {
372561e0011Smartijn 		if (len != NULL)
373561e0011Smartijn 			*v = elm->be_val;
374561e0011Smartijn 		else
375561e0011Smartijn 			*v = NULL;
376561e0011Smartijn 	}
377d4b95dc4Srob 	return 0;
378d4b95dc4Srob }
379d4b95dc4Srob 
380d4b95dc4Srob struct ber_element *
ober_add_null(struct ber_element * prev)381696b5899Stb ober_add_null(struct ber_element *prev)
382d4b95dc4Srob {
383d4b95dc4Srob 	struct ber_element *elm;
384d4b95dc4Srob 
385696b5899Stb 	if ((elm = ober_get_element(BER_TYPE_NULL)) == NULL)
386d4b95dc4Srob 		return NULL;
387d4b95dc4Srob 
388696b5899Stb 	ober_link_elements(prev, elm);
389d4b95dc4Srob 
390d4b95dc4Srob 	return elm;
391d4b95dc4Srob }
392d4b95dc4Srob 
393d4b95dc4Srob int
ober_get_null(struct ber_element * elm)394696b5899Stb ober_get_null(struct ber_element *elm)
395d4b95dc4Srob {
396d4b95dc4Srob 	if (elm->be_encoding != BER_TYPE_NULL)
397d4b95dc4Srob 		return -1;
398d4b95dc4Srob 
399d4b95dc4Srob 	return 0;
400d4b95dc4Srob }
401d4b95dc4Srob 
402d4b95dc4Srob struct ber_element *
ober_add_eoc(struct ber_element * prev)403696b5899Stb ober_add_eoc(struct ber_element *prev)
404d4b95dc4Srob {
405d4b95dc4Srob 	struct ber_element *elm;
406d4b95dc4Srob 
407696b5899Stb 	if ((elm = ober_get_element(BER_TYPE_EOC)) == NULL)
408d4b95dc4Srob 		return NULL;
409d4b95dc4Srob 
410696b5899Stb 	ober_link_elements(prev, elm);
411d4b95dc4Srob 
412d4b95dc4Srob 	return elm;
413d4b95dc4Srob }
414d4b95dc4Srob 
415d4b95dc4Srob int
ober_get_eoc(struct ber_element * elm)416696b5899Stb ober_get_eoc(struct ber_element *elm)
417d4b95dc4Srob {
418d4b95dc4Srob 	if (elm->be_encoding != BER_TYPE_EOC)
419d4b95dc4Srob 		return -1;
420d4b95dc4Srob 
421d4b95dc4Srob 	return 0;
422d4b95dc4Srob }
423d4b95dc4Srob 
424d4b95dc4Srob size_t
ober_oid2ber(struct ber_oid * o,u_int8_t * buf,size_t len)425696b5899Stb ober_oid2ber(struct ber_oid *o, u_int8_t *buf, size_t len)
426d4b95dc4Srob {
427d4b95dc4Srob 	u_int32_t	 v;
428d4b95dc4Srob 	u_int		 i, j = 0, k;
429d4b95dc4Srob 
430d4b95dc4Srob 	if (o->bo_n < BER_MIN_OID_LEN || o->bo_n > BER_MAX_OID_LEN ||
431d4b95dc4Srob 	    o->bo_id[0] > 2 || o->bo_id[1] > 40)
432d4b95dc4Srob 		return (0);
433d4b95dc4Srob 
434d4b95dc4Srob 	v = (o->bo_id[0] * 40) + o->bo_id[1];
435d4b95dc4Srob 	for (i = 2, j = 0; i <= o->bo_n; v = o->bo_id[i], i++) {
436d4b95dc4Srob 		for (k = 28; k >= 7; k -= 7) {
437d4b95dc4Srob 			if (v >= (u_int)(1 << k)) {
438d4b95dc4Srob 				if (len)
439d4b95dc4Srob 					buf[j] = v >> k | BER_TAG_MORE;
440d4b95dc4Srob 				j++;
441d4b95dc4Srob 			}
442d4b95dc4Srob 		}
443d4b95dc4Srob 		if (len)
444d4b95dc4Srob 			buf[j] = v & BER_TAG_TYPE_MASK;
445d4b95dc4Srob 		j++;
446d4b95dc4Srob 	}
447d4b95dc4Srob 
448d4b95dc4Srob 	return (j);
449d4b95dc4Srob }
450d4b95dc4Srob 
451d4b95dc4Srob int
ober_string2oid(const char * oidstr,struct ber_oid * o)452696b5899Stb ober_string2oid(const char *oidstr, struct ber_oid *o)
453d4b95dc4Srob {
454d4b95dc4Srob 	char			*sp, *p, str[BUFSIZ];
455d4b95dc4Srob 	const char		*errstr;
456d4b95dc4Srob 
457d4b95dc4Srob 	if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
458d4b95dc4Srob 		return (-1);
459d4b95dc4Srob 	memset(o, 0, sizeof(*o));
460d4b95dc4Srob 
461d4b95dc4Srob 	/* Parse OID strings in the common forms n.n.n, n_n_n_n, or n-n-n */
462d4b95dc4Srob 	for (p = sp = str; p != NULL; sp = p) {
463d4b95dc4Srob 		if ((p = strpbrk(p, "._-")) != NULL)
464d4b95dc4Srob 			*p++ = '\0';
465d4b95dc4Srob 		o->bo_id[o->bo_n++] = strtonum(sp, 0, UINT_MAX, &errstr);
466d4b95dc4Srob 		if (errstr || o->bo_n > BER_MAX_OID_LEN)
467d4b95dc4Srob 			return (-1);
468d4b95dc4Srob 	}
469d4b95dc4Srob 
470d4b95dc4Srob 	return (0);
471d4b95dc4Srob }
472d4b95dc4Srob 
473d4b95dc4Srob int
ober_oid_cmp(struct ber_oid * a,struct ber_oid * b)474696b5899Stb ober_oid_cmp(struct ber_oid *a, struct ber_oid *b)
475d4b95dc4Srob {
476893ac8ceSmartijn 	size_t	 i, min;
477d4b95dc4Srob 
478893ac8ceSmartijn 	min = a->bo_n < b->bo_n ? a->bo_n : b->bo_n;
479893ac8ceSmartijn 	for (i = 0; i < min; i++) {
480893ac8ceSmartijn 		if (a->bo_id[i] < b->bo_id[i])
481893ac8ceSmartijn 			return (-1);
482893ac8ceSmartijn 		if (a->bo_id[i] > b->bo_id[i])
483893ac8ceSmartijn 			return (1);
484893ac8ceSmartijn 	}
485893ac8ceSmartijn 	/* a is parent of b */
486893ac8ceSmartijn 	if (a->bo_n < b->bo_n)
487893ac8ceSmartijn 		return (-2);
488893ac8ceSmartijn 	/* a is child of b */
489893ac8ceSmartijn 	if (a->bo_n > b->bo_n)
490893ac8ceSmartijn 		return 2;
491d4b95dc4Srob 	return (0);
492d4b95dc4Srob }
493d4b95dc4Srob 
494d4b95dc4Srob struct ber_element *
ober_add_oid(struct ber_element * prev,struct ber_oid * o)495696b5899Stb ober_add_oid(struct ber_element *prev, struct ber_oid *o)
496d4b95dc4Srob {
497d4b95dc4Srob 	struct ber_element	*elm;
498d4b95dc4Srob 	u_int8_t		*buf;
499d4b95dc4Srob 	size_t			 len;
500d4b95dc4Srob 
501696b5899Stb 	if ((elm = ober_get_element(BER_TYPE_OBJECT)) == NULL)
502d4b95dc4Srob 		return (NULL);
503d4b95dc4Srob 
504696b5899Stb 	if ((len = ober_oid2ber(o, NULL, 0)) == 0)
505d4b95dc4Srob 		goto fail;
506d4b95dc4Srob 
507d4b95dc4Srob 	if ((buf = calloc(1, len)) == NULL)
508d4b95dc4Srob 		goto fail;
509d4b95dc4Srob 
510d4b95dc4Srob 	elm->be_val = buf;
511d4b95dc4Srob 	elm->be_len = len;
512d4b95dc4Srob 	elm->be_free = 1;
513d4b95dc4Srob 
514696b5899Stb 	if (ober_oid2ber(o, buf, len) != len)
515d4b95dc4Srob 		goto fail;
516d4b95dc4Srob 
517696b5899Stb 	ober_link_elements(prev, elm);
518d4b95dc4Srob 
519d4b95dc4Srob 	return (elm);
520d4b95dc4Srob 
521d4b95dc4Srob  fail:
522696b5899Stb 	ober_free_elements(elm);
523d4b95dc4Srob 	return (NULL);
524d4b95dc4Srob }
525d4b95dc4Srob 
526d4b95dc4Srob struct ber_element *
ober_add_noid(struct ber_element * prev,struct ber_oid * o,int n)527696b5899Stb ober_add_noid(struct ber_element *prev, struct ber_oid *o, int n)
528d4b95dc4Srob {
529d4b95dc4Srob 	struct ber_oid		 no;
530d4b95dc4Srob 
531d4b95dc4Srob 	if (n > BER_MAX_OID_LEN)
532d4b95dc4Srob 		return (NULL);
533d4b95dc4Srob 	no.bo_n = n;
534d4b95dc4Srob 	bcopy(&o->bo_id, &no.bo_id, sizeof(no.bo_id));
535d4b95dc4Srob 
536696b5899Stb 	return (ober_add_oid(prev, &no));
537d4b95dc4Srob }
538d4b95dc4Srob 
539d4b95dc4Srob struct ber_element *
ober_add_oidstring(struct ber_element * prev,const char * oidstr)540696b5899Stb ober_add_oidstring(struct ber_element *prev, const char *oidstr)
541d4b95dc4Srob {
542d4b95dc4Srob 	struct ber_oid		 o;
543d4b95dc4Srob 
544696b5899Stb 	if (ober_string2oid(oidstr, &o) == -1)
545d4b95dc4Srob 		return (NULL);
546d4b95dc4Srob 
547696b5899Stb 	return (ober_add_oid(prev, &o));
548d4b95dc4Srob }
549d4b95dc4Srob 
550d4b95dc4Srob int
ober_get_oid(struct ber_element * elm,struct ber_oid * o)551696b5899Stb ober_get_oid(struct ber_element *elm, struct ber_oid *o)
552d4b95dc4Srob {
553d4b95dc4Srob 	u_int8_t	*buf;
554d4b95dc4Srob 	size_t		 len, i = 0, j = 0;
555d4b95dc4Srob 
556d4b95dc4Srob 	if (elm->be_encoding != BER_TYPE_OBJECT)
557d4b95dc4Srob 		return (-1);
558d4b95dc4Srob 
559561e0011Smartijn 	if (o == NULL)
560561e0011Smartijn 		return 0;
561561e0011Smartijn 
562d4b95dc4Srob 	buf = elm->be_val;
563d4b95dc4Srob 	len = elm->be_len;
564d4b95dc4Srob 
565d4b95dc4Srob 	memset(o, 0, sizeof(*o));
566d4b95dc4Srob 	o->bo_id[j++] = buf[i] / 40;
567d4b95dc4Srob 	o->bo_id[j++] = buf[i++] % 40;
568d4b95dc4Srob 	for (; i < len && j < BER_MAX_OID_LEN; i++) {
569d4b95dc4Srob 		o->bo_id[j] = (o->bo_id[j] << 7) + (buf[i] & ~0x80);
570d4b95dc4Srob 		if (buf[i] & 0x80)
571d4b95dc4Srob 			continue;
572d4b95dc4Srob 		j++;
573d4b95dc4Srob 	}
574d4b95dc4Srob 	o->bo_n = j;
575d4b95dc4Srob 
576d4b95dc4Srob 	return (0);
577d4b95dc4Srob }
578d4b95dc4Srob 
579*40632fedSmartijn #define _MAX_SEQ		 128
580d4b95dc4Srob struct ber_element *
ober_printf_elements(struct ber_element * ber,char * fmt,...)581696b5899Stb ober_printf_elements(struct ber_element *ber, char *fmt, ...)
582d4b95dc4Srob {
583d4b95dc4Srob 	va_list			 ap;
584*40632fedSmartijn 	int			 d, class, level = 0;
585d4b95dc4Srob 	size_t			 len;
586d4b95dc4Srob 	unsigned int		 type;
587d4b95dc4Srob 	long long		 i;
588d4b95dc4Srob 	char			*s;
589d4b95dc4Srob 	void			*p;
590d4b95dc4Srob 	struct ber_oid		*o;
591*40632fedSmartijn 	struct ber_element	*parent[_MAX_SEQ], *e;
592*40632fedSmartijn 	struct ber_element	*origber = ber, *firstber = NULL;
593*40632fedSmartijn 
594*40632fedSmartijn 	memset(parent, 0, sizeof(struct ber_element *) * _MAX_SEQ);
595d4b95dc4Srob 
596d4b95dc4Srob 	va_start(ap, fmt);
597*40632fedSmartijn 
598d4b95dc4Srob 	while (*fmt) {
599d4b95dc4Srob 		switch (*fmt++) {
600d4b95dc4Srob 		case 'B':
601d4b95dc4Srob 			p = va_arg(ap, void *);
602d4b95dc4Srob 			len = va_arg(ap, size_t);
603696b5899Stb 			if ((ber = ober_add_bitstring(ber, p, len)) == NULL)
604d4b95dc4Srob 				goto fail;
605d4b95dc4Srob 			break;
606d4b95dc4Srob 		case 'b':
607d4b95dc4Srob 			d = va_arg(ap, int);
608696b5899Stb 			if ((ber = ober_add_boolean(ber, d)) == NULL)
609d4b95dc4Srob 				goto fail;
610d4b95dc4Srob 			break;
611d4b95dc4Srob 		case 'd':
612d4b95dc4Srob 			d = va_arg(ap, int);
613696b5899Stb 			if ((ber = ober_add_integer(ber, d)) == NULL)
614d4b95dc4Srob 				goto fail;
615d4b95dc4Srob 			break;
616d4b95dc4Srob 		case 'e':
617d4b95dc4Srob 			e = va_arg(ap, struct ber_element *);
618696b5899Stb 			ober_link_elements(ber, e);
619d4b95dc4Srob 			break;
620d4b95dc4Srob 		case 'E':
621d4b95dc4Srob 			i = va_arg(ap, long long);
622696b5899Stb 			if ((ber = ober_add_enumerated(ber, i)) == NULL)
623d4b95dc4Srob 				goto fail;
624d4b95dc4Srob 			break;
625d4b95dc4Srob 		case 'i':
626d4b95dc4Srob 			i = va_arg(ap, long long);
627696b5899Stb 			if ((ber = ober_add_integer(ber, i)) == NULL)
628d4b95dc4Srob 				goto fail;
629d4b95dc4Srob 			break;
630d4b95dc4Srob 		case 'O':
631d4b95dc4Srob 			o = va_arg(ap, struct ber_oid *);
632696b5899Stb 			if ((ber = ober_add_oid(ber, o)) == NULL)
633d4b95dc4Srob 				goto fail;
634d4b95dc4Srob 			break;
635d4b95dc4Srob 		case 'o':
636d4b95dc4Srob 			s = va_arg(ap, char *);
637696b5899Stb 			if ((ber = ober_add_oidstring(ber, s)) == NULL)
638d4b95dc4Srob 				goto fail;
639d4b95dc4Srob 			break;
640d4b95dc4Srob 		case 's':
641d4b95dc4Srob 			s = va_arg(ap, char *);
642696b5899Stb 			if ((ber = ober_add_string(ber, s)) == NULL)
643d4b95dc4Srob 				goto fail;
644d4b95dc4Srob 			break;
645d4b95dc4Srob 		case 't':
646d4b95dc4Srob 			class = va_arg(ap, int);
647d4b95dc4Srob 			type = va_arg(ap, unsigned int);
648696b5899Stb 			ober_set_header(ber, class, type);
649d4b95dc4Srob 			break;
650d4b95dc4Srob 		case 'x':
651d4b95dc4Srob 			s = va_arg(ap, char *);
652d4b95dc4Srob 			len = va_arg(ap, size_t);
653696b5899Stb 			if ((ber = ober_add_nstring(ber, s, len)) == NULL)
654d4b95dc4Srob 				goto fail;
655d4b95dc4Srob 			break;
656d4b95dc4Srob 		case '0':
657696b5899Stb 			if ((ber = ober_add_null(ber)) == NULL)
658d4b95dc4Srob 				goto fail;
659d4b95dc4Srob 			break;
660d4b95dc4Srob 		case '{':
661*40632fedSmartijn 			if (level >= _MAX_SEQ-1)
662d4b95dc4Srob 				goto fail;
663*40632fedSmartijn 			if ((ber= ober_add_sequence(ber)) == NULL)
664*40632fedSmartijn 				goto fail;
665*40632fedSmartijn 			parent[level++] = ber;
666d4b95dc4Srob 			break;
667d4b95dc4Srob 		case '(':
668*40632fedSmartijn 			if (level >= _MAX_SEQ-1)
669d4b95dc4Srob 				goto fail;
670*40632fedSmartijn 			if ((ber = ober_add_set(ber)) == NULL)
671*40632fedSmartijn 				goto fail;
672*40632fedSmartijn 			parent[level++] = ber;
673d4b95dc4Srob 			break;
674d4b95dc4Srob 		case '}':
675d4b95dc4Srob 		case ')':
676*40632fedSmartijn 			if (level <= 0 || parent[level - 1] == NULL)
677*40632fedSmartijn 				goto fail;
678*40632fedSmartijn 			ber = parent[--level];
679d4b95dc4Srob 			break;
680d4b95dc4Srob 		case '.':
681696b5899Stb 			if ((e = ober_add_eoc(ber)) == NULL)
682d4b95dc4Srob 				goto fail;
683d4b95dc4Srob 			ber = e;
684d4b95dc4Srob 			break;
685d4b95dc4Srob 		default:
686d4b95dc4Srob 			break;
687d4b95dc4Srob 		}
688*40632fedSmartijn 		if (firstber == NULL)
689*40632fedSmartijn 			firstber = ber;
690d4b95dc4Srob 	}
691d4b95dc4Srob 	va_end(ap);
692d4b95dc4Srob 
693d4b95dc4Srob 	return (ber);
694d4b95dc4Srob  fail:
695*40632fedSmartijn 	if (origber != NULL)
696*40632fedSmartijn 		ober_unlink_elements(origber);
697*40632fedSmartijn 	ober_free_elements(firstber);
698d4b95dc4Srob 	return (NULL);
699d4b95dc4Srob }
700d4b95dc4Srob 
701d4b95dc4Srob int
ober_scanf_elements(struct ber_element * ber,char * fmt,...)702696b5899Stb ober_scanf_elements(struct ber_element *ber, char *fmt, ...)
703d4b95dc4Srob {
704d4b95dc4Srob 	va_list			 ap;
705d4b95dc4Srob 	int			*d, level = -1;
706d4b95dc4Srob 	unsigned int		*t;
707d4b95dc4Srob 	long long		*i, l;
708d4b95dc4Srob 	void			**ptr;
709d4b95dc4Srob 	size_t			*len, ret = 0, n = strlen(fmt);
710d4b95dc4Srob 	char			**s;
711d4b95dc4Srob 	off_t			*pos;
712d4b95dc4Srob 	struct ber_oid		*o;
713d4b95dc4Srob 	struct ber_element	*parent[_MAX_SEQ], **e;
714d4b95dc4Srob 
715d4b95dc4Srob 	memset(parent, 0, sizeof(struct ber_element *) * _MAX_SEQ);
716d4b95dc4Srob 
717d4b95dc4Srob 	va_start(ap, fmt);
718d4b95dc4Srob 	while (*fmt) {
719b8d19846Smartijn 		if (ber == NULL && *fmt != '$' && *fmt != '}' && *fmt != ')')
720497d37e3Smartijn 			goto fail;
721d4b95dc4Srob 		switch (*fmt++) {
722b8d19846Smartijn 		case '$':
723b8d19846Smartijn 			if (ber != NULL)
724b8d19846Smartijn 				goto fail;
725b8d19846Smartijn 			ret++;
726b8d19846Smartijn 			continue;
727d4b95dc4Srob 		case 'B':
728d4b95dc4Srob 			ptr = va_arg(ap, void **);
729d4b95dc4Srob 			len = va_arg(ap, size_t *);
730696b5899Stb 			if (ober_get_bitstring(ber, ptr, len) == -1)
731d4b95dc4Srob 				goto fail;
732d4b95dc4Srob 			ret++;
733d4b95dc4Srob 			break;
734d4b95dc4Srob 		case 'b':
735d4b95dc4Srob 			d = va_arg(ap, int *);
736696b5899Stb 			if (ober_get_boolean(ber, d) == -1)
737d4b95dc4Srob 				goto fail;
738d4b95dc4Srob 			ret++;
739d4b95dc4Srob 			break;
740d4b95dc4Srob 		case 'd':
741d4b95dc4Srob 			d = va_arg(ap, int *);
742696b5899Stb 			if (ober_get_integer(ber, &l) == -1)
743d4b95dc4Srob 				goto fail;
744561e0011Smartijn 			if (d != NULL)
745d4b95dc4Srob 				*d = l;
746d4b95dc4Srob 			ret++;
747d4b95dc4Srob 			break;
748d4b95dc4Srob 		case 'e':
749d4b95dc4Srob 			e = va_arg(ap, struct ber_element **);
750d4b95dc4Srob 			*e = ber;
751d4b95dc4Srob 			ret++;
7522b859d28Smartijn 			continue;
753d4b95dc4Srob 		case 'E':
754d4b95dc4Srob 			i = va_arg(ap, long long *);
755696b5899Stb 			if (ober_get_enumerated(ber, i) == -1)
756d4b95dc4Srob 				goto fail;
757d4b95dc4Srob 			ret++;
758d4b95dc4Srob 			break;
759d4b95dc4Srob 		case 'i':
760d4b95dc4Srob 			i = va_arg(ap, long long *);
761696b5899Stb 			if (ober_get_integer(ber, i) == -1)
762d4b95dc4Srob 				goto fail;
763d4b95dc4Srob 			ret++;
764d4b95dc4Srob 			break;
765d4b95dc4Srob 		case 'o':
766d4b95dc4Srob 			o = va_arg(ap, struct ber_oid *);
767696b5899Stb 			if (ober_get_oid(ber, o) == -1)
768d4b95dc4Srob 				goto fail;
769d4b95dc4Srob 			ret++;
770d4b95dc4Srob 			break;
771d4b95dc4Srob 		case 'S':
772d4b95dc4Srob 			ret++;
773d4b95dc4Srob 			break;
774d4b95dc4Srob 		case 's':
775d4b95dc4Srob 			s = va_arg(ap, char **);
776696b5899Stb 			if (ober_get_string(ber, s) == -1)
777d4b95dc4Srob 				goto fail;
778d4b95dc4Srob 			ret++;
779d4b95dc4Srob 			break;
780d4b95dc4Srob 		case 't':
781d4b95dc4Srob 			d = va_arg(ap, int *);
782d4b95dc4Srob 			t = va_arg(ap, unsigned int *);
783561e0011Smartijn 			if (d != NULL)
784d4b95dc4Srob 				*d = ber->be_class;
785561e0011Smartijn 			if (t != NULL)
786d4b95dc4Srob 				*t = ber->be_type;
787d4b95dc4Srob 			ret++;
788d4b95dc4Srob 			continue;
789d4b95dc4Srob 		case 'x':
790d4b95dc4Srob 			ptr = va_arg(ap, void **);
791d4b95dc4Srob 			len = va_arg(ap, size_t *);
792696b5899Stb 			if (ober_get_nstring(ber, ptr, len) == -1)
793d4b95dc4Srob 				goto fail;
794d4b95dc4Srob 			ret++;
795d4b95dc4Srob 			break;
796d4b95dc4Srob 		case '0':
797d4b95dc4Srob 			if (ber->be_encoding != BER_TYPE_NULL)
798d4b95dc4Srob 				goto fail;
799d4b95dc4Srob 			ret++;
800d4b95dc4Srob 			break;
801d4b95dc4Srob 		case '.':
802d4b95dc4Srob 			if (ber->be_encoding != BER_TYPE_EOC)
803d4b95dc4Srob 				goto fail;
804d4b95dc4Srob 			ret++;
805d4b95dc4Srob 			break;
806d4b95dc4Srob 		case 'p':
807d4b95dc4Srob 			pos = va_arg(ap, off_t *);
808696b5899Stb 			*pos = ober_getpos(ber);
809d4b95dc4Srob 			ret++;
810d4b95dc4Srob 			continue;
811d4b95dc4Srob 		case '{':
812d4b95dc4Srob 		case '(':
813d4b95dc4Srob 			if (ber->be_encoding != BER_TYPE_SEQUENCE &&
814d4b95dc4Srob 			    ber->be_encoding != BER_TYPE_SET)
815d4b95dc4Srob 				goto fail;
816ad1cd115Sgerhard 			if (level >= _MAX_SEQ-1)
817d4b95dc4Srob 				goto fail;
818d4b95dc4Srob 			parent[++level] = ber;
819d4b95dc4Srob 			ber = ber->be_sub;
820d4b95dc4Srob 			ret++;
821d4b95dc4Srob 			continue;
822d4b95dc4Srob 		case '}':
823d4b95dc4Srob 		case ')':
824f273e380Srob 			if (level < 0 || parent[level] == NULL)
825d4b95dc4Srob 				goto fail;
826d4b95dc4Srob 			ber = parent[level--];
827d4b95dc4Srob 			ret++;
828d4b95dc4Srob 			break;
829d4b95dc4Srob 		default:
830d4b95dc4Srob 			goto fail;
831d4b95dc4Srob 		}
832d4b95dc4Srob 
833d4b95dc4Srob 		ber = ber->be_next;
834d4b95dc4Srob 	}
835d4b95dc4Srob 	va_end(ap);
836d4b95dc4Srob 	return (ret == n ? 0 : -1);
837d4b95dc4Srob 
838d4b95dc4Srob  fail:
839d4b95dc4Srob 	va_end(ap);
840d4b95dc4Srob 	return (-1);
841d4b95dc4Srob 
842d4b95dc4Srob }
843d4b95dc4Srob 
844d4b95dc4Srob ssize_t
ober_get_writebuf(struct ber * b,void ** buf)845696b5899Stb ober_get_writebuf(struct ber *b, void **buf)
846d4b95dc4Srob {
847d4b95dc4Srob 	if (b->br_wbuf == NULL)
848d4b95dc4Srob 		return -1;
849d4b95dc4Srob 	*buf = b->br_wbuf;
850d4b95dc4Srob 	return (b->br_wend - b->br_wbuf);
851d4b95dc4Srob }
852d4b95dc4Srob 
853d4b95dc4Srob /*
854d4b95dc4Srob  * write ber elements to the write buffer
855d4b95dc4Srob  *
856d4b95dc4Srob  * params:
857d4b95dc4Srob  *	ber	holds the destination write buffer byte stream
858d4b95dc4Srob  *	root	fully populated element tree
859d4b95dc4Srob  *
860d4b95dc4Srob  * returns:
861d4b95dc4Srob  *	>=0	number of bytes written
862d4b95dc4Srob  *	-1	on failure and sets errno
863d4b95dc4Srob  */
864d4b95dc4Srob ssize_t
ober_write_elements(struct ber * ber,struct ber_element * root)865696b5899Stb ober_write_elements(struct ber *ber, struct ber_element *root)
866d4b95dc4Srob {
867d4b95dc4Srob 	size_t len;
868d4b95dc4Srob 
869d4b95dc4Srob 	/* calculate length because only the definite form is required */
870696b5899Stb 	len = ober_calc_len(root);
871d4b95dc4Srob 	DPRINTF("write ber element of %zd bytes length\n", len);
872d4b95dc4Srob 
873d4b95dc4Srob 	if (ber->br_wbuf != NULL && ber->br_wbuf + len > ber->br_wend) {
874d4b95dc4Srob 		free(ber->br_wbuf);
875d4b95dc4Srob 		ber->br_wbuf = NULL;
876d4b95dc4Srob 	}
877d4b95dc4Srob 	if (ber->br_wbuf == NULL) {
878d4b95dc4Srob 		if ((ber->br_wbuf = malloc(len)) == NULL)
879d4b95dc4Srob 			return -1;
880d4b95dc4Srob 		ber->br_wend = ber->br_wbuf + len;
881d4b95dc4Srob 	}
882d4b95dc4Srob 
883d4b95dc4Srob 	/* reset write pointer */
884d4b95dc4Srob 	ber->br_wptr = ber->br_wbuf;
885d4b95dc4Srob 
886696b5899Stb 	if (ober_dump_element(ber, root) == -1)
887d4b95dc4Srob 		return -1;
888d4b95dc4Srob 
889d4b95dc4Srob 	return (len);
890d4b95dc4Srob }
891d4b95dc4Srob 
892d4b95dc4Srob void
ober_set_readbuf(struct ber * b,void * buf,size_t len)893696b5899Stb ober_set_readbuf(struct ber *b, void *buf, size_t len)
894d4b95dc4Srob {
895d4b95dc4Srob 	b->br_rbuf = b->br_rptr = buf;
896d4b95dc4Srob 	b->br_rend = (u_int8_t *)buf + len;
897d4b95dc4Srob }
898d4b95dc4Srob 
899d4b95dc4Srob /*
900d4b95dc4Srob  * read ber elements from the read buffer
901d4b95dc4Srob  *
902d4b95dc4Srob  * params:
903d4b95dc4Srob  *	ber	holds a fully populated read buffer byte stream
904d4b95dc4Srob  *	root	if NULL, build up an element tree from what we receive on
905d4b95dc4Srob  *		the wire. If not null, use the specified encoding for the
906d4b95dc4Srob  *		elements received.
907d4b95dc4Srob  *
908d4b95dc4Srob  * returns:
909d4b95dc4Srob  *	!=NULL, elements read and store in the ber_element tree
910d4b95dc4Srob  *	NULL, type mismatch or read error
911d4b95dc4Srob  */
912d4b95dc4Srob struct ber_element *
ober_read_elements(struct ber * ber,struct ber_element * elm)913696b5899Stb ober_read_elements(struct ber *ber, struct ber_element *elm)
914d4b95dc4Srob {
915d4b95dc4Srob 	struct ber_element *root = elm;
916d4b95dc4Srob 
917d4b95dc4Srob 	if (root == NULL) {
918696b5899Stb 		if ((root = ober_get_element(0)) == NULL)
919d4b95dc4Srob 			return NULL;
920d4b95dc4Srob 	}
921d4b95dc4Srob 
922d4b95dc4Srob 	DPRINTF("read ber elements, root %p\n", root);
923d4b95dc4Srob 
924696b5899Stb 	if (ober_read_element(ber, root) == -1) {
925d4b95dc4Srob 		/* Cleanup if root was allocated by us */
926d4b95dc4Srob 		if (elm == NULL)
927696b5899Stb 			ober_free_elements(root);
928d4b95dc4Srob 		return NULL;
929d4b95dc4Srob 	}
930d4b95dc4Srob 
931d4b95dc4Srob 	return root;
932d4b95dc4Srob }
933d4b95dc4Srob 
934d4b95dc4Srob off_t
ober_getpos(struct ber_element * elm)935696b5899Stb ober_getpos(struct ber_element *elm)
936d4b95dc4Srob {
937d4b95dc4Srob 	return elm->be_offs;
938d4b95dc4Srob }
939d4b95dc4Srob 
94063beb567Smartijn struct ber_element *
ober_dup(struct ber_element * orig)94163beb567Smartijn ober_dup(struct ber_element *orig)
94263beb567Smartijn {
94363beb567Smartijn 	struct ber_element *new;
94463beb567Smartijn 
94563beb567Smartijn 	if ((new = malloc(sizeof(*new))) == NULL)
94663beb567Smartijn 		return NULL;
94763beb567Smartijn 	memcpy(new, orig, sizeof(*new));
94863beb567Smartijn 	new->be_next = NULL;
94963beb567Smartijn 	new->be_sub = NULL;
95063beb567Smartijn 
95163beb567Smartijn 	if (orig->be_next != NULL) {
95263beb567Smartijn 		if ((new->be_next = ober_dup(orig->be_next)) == NULL)
95363beb567Smartijn 			goto fail;
95463beb567Smartijn 	}
95563beb567Smartijn 	if (orig->be_encoding == BER_TYPE_SEQUENCE ||
95663beb567Smartijn 	    orig->be_encoding == BER_TYPE_SET) {
95763beb567Smartijn 		if (orig->be_sub != NULL) {
95863beb567Smartijn 			if ((new->be_sub = ober_dup(orig->be_sub)) == NULL)
95963beb567Smartijn 				goto fail;
96063beb567Smartijn 		}
96163beb567Smartijn 	} else if (orig->be_encoding == BER_TYPE_OCTETSTRING ||
96263beb567Smartijn 	    orig->be_encoding == BER_TYPE_BITSTRING ||
96363beb567Smartijn 	    orig->be_encoding == BER_TYPE_OBJECT) {
96463beb567Smartijn 		if (orig->be_val != NULL) {
96563beb567Smartijn 			if ((new->be_val = malloc(orig->be_len)) == NULL)
96663beb567Smartijn 				goto fail;
96763beb567Smartijn 			memcpy(new->be_val, orig->be_val, orig->be_len);
96863beb567Smartijn 		}
96963beb567Smartijn 	} else
97063beb567Smartijn 		new->be_numeric = orig->be_numeric;
97163beb567Smartijn 	return new;
97263beb567Smartijn  fail:
97363beb567Smartijn 	ober_free_elements(new);
97463beb567Smartijn 	return NULL;
97563beb567Smartijn }
97663beb567Smartijn 
977d4b95dc4Srob void
ober_free_element(struct ber_element * root)978696b5899Stb ober_free_element(struct ber_element *root)
979d4b95dc4Srob {
980d4b95dc4Srob 	if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
981d4b95dc4Srob 	    root->be_encoding == BER_TYPE_SET))
982696b5899Stb 		ober_free_elements(root->be_sub);
983d4b95dc4Srob 	if (root->be_free && (root->be_encoding == BER_TYPE_OCTETSTRING ||
984d4b95dc4Srob 	    root->be_encoding == BER_TYPE_BITSTRING ||
985d4b95dc4Srob 	    root->be_encoding == BER_TYPE_OBJECT))
986d4b95dc4Srob 		free(root->be_val);
987d4b95dc4Srob 	free(root);
988d4b95dc4Srob }
989d4b95dc4Srob 
990d4b95dc4Srob void
ober_free_elements(struct ber_element * root)991696b5899Stb ober_free_elements(struct ber_element *root)
992d4b95dc4Srob {
993d4b95dc4Srob 	if (root == NULL)
994d4b95dc4Srob 		return;
995d4b95dc4Srob 	if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
996d4b95dc4Srob 	    root->be_encoding == BER_TYPE_SET))
997696b5899Stb 		ober_free_elements(root->be_sub);
998d4b95dc4Srob 	if (root->be_next)
999696b5899Stb 		ober_free_elements(root->be_next);
1000d4b95dc4Srob 	if (root->be_free && (root->be_encoding == BER_TYPE_OCTETSTRING ||
1001d4b95dc4Srob 	    root->be_encoding == BER_TYPE_BITSTRING ||
1002d4b95dc4Srob 	    root->be_encoding == BER_TYPE_OBJECT))
1003d4b95dc4Srob 		free(root->be_val);
1004d4b95dc4Srob 	free(root);
1005d4b95dc4Srob }
1006d4b95dc4Srob 
1007d4b95dc4Srob size_t
ober_calc_len(struct ber_element * root)1008696b5899Stb ober_calc_len(struct ber_element *root)
1009d4b95dc4Srob {
1010d4b95dc4Srob 	unsigned int t;
1011d4b95dc4Srob 	size_t s;
1012d4b95dc4Srob 	size_t size = 2;	/* minimum 1 byte head and 1 byte size */
1013d4b95dc4Srob 
1014d4b95dc4Srob 	/* calculate the real length of a sequence or set */
1015d4b95dc4Srob 	if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
1016d4b95dc4Srob 	    root->be_encoding == BER_TYPE_SET))
1017696b5899Stb 		root->be_len = ober_calc_len(root->be_sub);
1018d4b95dc4Srob 
1019d4b95dc4Srob 	/* fix header length for extended types */
1020d4b95dc4Srob 	if (root->be_type > BER_TYPE_SINGLE_MAX)
1021d4b95dc4Srob 		for (t = root->be_type; t > 0; t >>= 7)
1022d4b95dc4Srob 			size++;
1023d4b95dc4Srob 	if (root->be_len >= BER_TAG_MORE)
1024d4b95dc4Srob 		for (s = root->be_len; s > 0; s >>= 8)
1025d4b95dc4Srob 			size++;
1026d4b95dc4Srob 
1027d4b95dc4Srob 	/* calculate the length of the following elements */
1028d4b95dc4Srob 	if (root->be_next)
1029696b5899Stb 		size += ober_calc_len(root->be_next);
1030d4b95dc4Srob 
1031d4b95dc4Srob 	/* This is an empty element, do not use a minimal size */
1032d4b95dc4Srob 	if (root->be_class == BER_CLASS_UNIVERSAL &&
1033d4b95dc4Srob 	    root->be_type == BER_TYPE_EOC && root->be_len == 0)
1034d4b95dc4Srob 		return (0);
1035d4b95dc4Srob 
1036d4b95dc4Srob 	return (root->be_len + size);
1037d4b95dc4Srob }
1038d4b95dc4Srob 
1039d4b95dc4Srob void
ober_set_application(struct ber * b,unsigned int (* cb)(struct ber_element *))1040696b5899Stb ober_set_application(struct ber *b, unsigned int (*cb)(struct ber_element *))
1041d4b95dc4Srob {
1042d4b95dc4Srob 	b->br_application = cb;
1043d4b95dc4Srob }
1044d4b95dc4Srob 
1045d4b95dc4Srob void
ober_set_writecallback(struct ber_element * elm,void (* cb)(void *,size_t),void * arg)1046696b5899Stb ober_set_writecallback(struct ber_element *elm, void (*cb)(void *, size_t),
1047d4b95dc4Srob     void *arg)
1048d4b95dc4Srob {
1049d4b95dc4Srob 	elm->be_cb = cb;
1050d4b95dc4Srob 	elm->be_cbarg = arg;
1051d4b95dc4Srob }
1052d4b95dc4Srob 
1053d4b95dc4Srob void
ober_free(struct ber * b)1054696b5899Stb ober_free(struct ber *b)
1055d4b95dc4Srob {
1056d4b95dc4Srob 	free(b->br_wbuf);
1057d4b95dc4Srob }
1058d4b95dc4Srob 
1059d4b95dc4Srob /*
1060d4b95dc4Srob  * internal functions
1061d4b95dc4Srob  */
1062d4b95dc4Srob 
1063d4b95dc4Srob static int
ober_dump_element(struct ber * ber,struct ber_element * root)1064696b5899Stb ober_dump_element(struct ber *ber, struct ber_element *root)
1065d4b95dc4Srob {
1066d4b95dc4Srob 	unsigned long long l;
1067d4b95dc4Srob 	int i;
1068d4b95dc4Srob 	uint8_t u;
1069d4b95dc4Srob 
1070696b5899Stb 	ober_dump_header(ber, root);
1071d4b95dc4Srob 	if (root->be_cb)
1072d4b95dc4Srob 		root->be_cb(root->be_cbarg, ber->br_wptr - ber->br_wbuf);
1073d4b95dc4Srob 
1074d4b95dc4Srob 	switch (root->be_encoding) {
1075d4b95dc4Srob 	case BER_TYPE_BOOLEAN:
1076d4b95dc4Srob 	case BER_TYPE_INTEGER:
1077d4b95dc4Srob 	case BER_TYPE_ENUMERATED:
1078d4b95dc4Srob 		l = (unsigned long long)root->be_numeric;
1079d4b95dc4Srob 		for (i = root->be_len; i > 0; i--) {
1080d4b95dc4Srob 			u = (l >> ((i - 1) * 8)) & 0xff;
1081696b5899Stb 			ober_putc(ber, u);
1082d4b95dc4Srob 		}
1083d4b95dc4Srob 		break;
1084d4b95dc4Srob 	case BER_TYPE_BITSTRING:
1085d4b95dc4Srob 	case BER_TYPE_OCTETSTRING:
1086d4b95dc4Srob 	case BER_TYPE_OBJECT:
1087696b5899Stb 		ober_write(ber, root->be_val, root->be_len);
1088d4b95dc4Srob 		break;
1089d4b95dc4Srob 	case BER_TYPE_NULL:	/* no payload */
1090d4b95dc4Srob 	case BER_TYPE_EOC:
1091d4b95dc4Srob 		break;
1092d4b95dc4Srob 	case BER_TYPE_SEQUENCE:
1093d4b95dc4Srob 	case BER_TYPE_SET:
1094696b5899Stb 		if (root->be_sub && ober_dump_element(ber, root->be_sub) == -1)
1095d4b95dc4Srob 			return -1;
1096d4b95dc4Srob 		break;
1097d4b95dc4Srob 	}
1098d4b95dc4Srob 
1099d4b95dc4Srob 	if (root->be_next == NULL)
1100d4b95dc4Srob 		return 0;
1101696b5899Stb 	return ober_dump_element(ber, root->be_next);
1102d4b95dc4Srob }
1103d4b95dc4Srob 
1104d4b95dc4Srob static void
ober_dump_header(struct ber * ber,struct ber_element * root)1105696b5899Stb ober_dump_header(struct ber *ber, struct ber_element *root)
1106d4b95dc4Srob {
1107d4b95dc4Srob 	u_char	id = 0, t, buf[5];
1108d4b95dc4Srob 	unsigned int type;
1109d4b95dc4Srob 	size_t size;
1110d4b95dc4Srob 
1111d4b95dc4Srob 	/* class universal, type encoding depending on type value */
1112d4b95dc4Srob 	/* length encoding */
1113d4b95dc4Srob 	if (root->be_type <= BER_TYPE_SINGLE_MAX) {
1114d4b95dc4Srob 		id = root->be_type | (root->be_class << BER_CLASS_SHIFT);
1115d4b95dc4Srob 		if (root->be_encoding == BER_TYPE_SEQUENCE ||
1116d4b95dc4Srob 		    root->be_encoding == BER_TYPE_SET)
1117d4b95dc4Srob 			id |= BER_TYPE_CONSTRUCTED;
1118d4b95dc4Srob 
1119696b5899Stb 		ober_putc(ber, id);
1120d4b95dc4Srob 	} else {
1121d4b95dc4Srob 		id = BER_TAG_MASK | (root->be_class << BER_CLASS_SHIFT);
1122d4b95dc4Srob 		if (root->be_encoding == BER_TYPE_SEQUENCE ||
1123d4b95dc4Srob 		    root->be_encoding == BER_TYPE_SET)
1124d4b95dc4Srob 			id |= BER_TYPE_CONSTRUCTED;
1125d4b95dc4Srob 
1126696b5899Stb 		ober_putc(ber, id);
1127d4b95dc4Srob 
1128d4b95dc4Srob 		for (t = 0, type = root->be_type; type > 0; type >>= 7)
1129d4b95dc4Srob 			buf[t++] = type & ~BER_TAG_MORE;
1130d4b95dc4Srob 
1131d4b95dc4Srob 		while (t-- > 0) {
1132d4b95dc4Srob 			if (t > 0)
1133d4b95dc4Srob 				buf[t] |= BER_TAG_MORE;
1134696b5899Stb 			ober_putc(ber, buf[t]);
1135d4b95dc4Srob 		}
1136d4b95dc4Srob 	}
1137d4b95dc4Srob 
1138d4b95dc4Srob 	if (root->be_len < BER_TAG_MORE) {
1139d4b95dc4Srob 		/* short form */
1140696b5899Stb 		ober_putc(ber, root->be_len);
1141d4b95dc4Srob 	} else {
1142d4b95dc4Srob 		for (t = 0, size = root->be_len; size > 0; size >>= 8)
1143d4b95dc4Srob 			buf[t++] = size & 0xff;
1144d4b95dc4Srob 
1145696b5899Stb 		ober_putc(ber, t | BER_TAG_MORE);
1146d4b95dc4Srob 
1147d4b95dc4Srob 		while (t > 0)
1148696b5899Stb 			ober_putc(ber, buf[--t]);
1149d4b95dc4Srob 	}
1150d4b95dc4Srob }
1151d4b95dc4Srob 
1152d4b95dc4Srob static void
ober_putc(struct ber * ber,u_char c)1153696b5899Stb ober_putc(struct ber *ber, u_char c)
1154d4b95dc4Srob {
1155d4b95dc4Srob 	if (ber->br_wptr + 1 <= ber->br_wend)
1156d4b95dc4Srob 		*ber->br_wptr = c;
1157d4b95dc4Srob 	ber->br_wptr++;
1158d4b95dc4Srob }
1159d4b95dc4Srob 
1160d4b95dc4Srob static void
ober_write(struct ber * ber,void * buf,size_t len)1161696b5899Stb ober_write(struct ber *ber, void *buf, size_t len)
1162d4b95dc4Srob {
1163d4b95dc4Srob 	if (ber->br_wptr + len <= ber->br_wend)
1164d4b95dc4Srob 		bcopy(buf, ber->br_wptr, len);
1165d4b95dc4Srob 	ber->br_wptr += len;
1166d4b95dc4Srob }
1167d4b95dc4Srob 
1168d4b95dc4Srob /*
1169d4b95dc4Srob  * extract a BER encoded tag. There are two types, a short and long form.
1170d4b95dc4Srob  */
1171d4b95dc4Srob static ssize_t
get_id(struct ber * b,unsigned int * tag,int * class,int * cstruct)1172d4b95dc4Srob get_id(struct ber *b, unsigned int *tag, int *class, int *cstruct)
1173d4b95dc4Srob {
1174d4b95dc4Srob 	u_char u;
1175d4b95dc4Srob 	size_t i = 0;
1176d4b95dc4Srob 	unsigned int t = 0;
1177d4b95dc4Srob 
1178696b5899Stb 	if (ober_getc(b, &u) == -1)
1179d4b95dc4Srob 		return -1;
1180d4b95dc4Srob 
1181d4b95dc4Srob 	*class = (u >> BER_CLASS_SHIFT) & BER_CLASS_MASK;
1182d4b95dc4Srob 	*cstruct = (u & BER_TYPE_CONSTRUCTED) == BER_TYPE_CONSTRUCTED;
1183d4b95dc4Srob 
1184d4b95dc4Srob 	if ((u & BER_TAG_MASK) != BER_TAG_MASK) {
1185d4b95dc4Srob 		*tag = u & BER_TAG_MASK;
1186d4b95dc4Srob 		return 1;
1187d4b95dc4Srob 	}
1188d4b95dc4Srob 
1189d4b95dc4Srob 	do {
1190696b5899Stb 		if (ober_getc(b, &u) == -1)
1191d4b95dc4Srob 			return -1;
11929248c219Srob 
11939248c219Srob 		/* enforce minimal number of octets for tag > 30 */
11949248c219Srob 		if (i == 0 && (u & ~BER_TAG_MORE) == 0) {
11959248c219Srob 			errno = EINVAL;
11969248c219Srob 			return -1;
11979248c219Srob 		}
11989248c219Srob 
1199d4b95dc4Srob 		t = (t << 7) | (u & ~BER_TAG_MORE);
1200d4b95dc4Srob 		i++;
1201d4b95dc4Srob 		if (i > sizeof(unsigned int)) {
1202d4b95dc4Srob 			errno = ERANGE;
1203d4b95dc4Srob 			return -1;
1204d4b95dc4Srob 		}
1205d4b95dc4Srob 	} while (u & BER_TAG_MORE);
1206d4b95dc4Srob 
1207d4b95dc4Srob 	*tag = t;
1208d4b95dc4Srob 	return i + 1;
1209d4b95dc4Srob }
1210d4b95dc4Srob 
1211d4b95dc4Srob /*
1212d4b95dc4Srob  * extract length of a ber object -- if length is unknown an error is returned.
1213d4b95dc4Srob  */
1214d4b95dc4Srob static ssize_t
get_len(struct ber * b,ssize_t * len)1215d4b95dc4Srob get_len(struct ber *b, ssize_t *len)
1216d4b95dc4Srob {
1217d4b95dc4Srob 	u_char	u, n;
1218d4b95dc4Srob 	ssize_t	s, r;
1219d4b95dc4Srob 
1220696b5899Stb 	if (ober_getc(b, &u) == -1)
1221d4b95dc4Srob 		return -1;
1222d4b95dc4Srob 	if ((u & BER_TAG_MORE) == 0) {
1223d4b95dc4Srob 		/* short form */
1224d4b95dc4Srob 		*len = u;
1225d4b95dc4Srob 		return 1;
1226d4b95dc4Srob 	}
1227d4b95dc4Srob 
1228d4b95dc4Srob 	if (u == 0x80) {
1229d4b95dc4Srob 		/* Indefinite length not supported. */
1230d4b95dc4Srob 		errno = EINVAL;
1231d4b95dc4Srob 		return -1;
1232d4b95dc4Srob 	}
1233d4b95dc4Srob 
12344880bb40Srob 	if (u == 0xff) {
12354880bb40Srob 		/* Reserved for future use. */
12364880bb40Srob 		errno = EINVAL;
12374880bb40Srob 		return -1;
12384880bb40Srob 	}
12394880bb40Srob 
1240d4b95dc4Srob 	n = u & ~BER_TAG_MORE;
1241260378dfSrob 	/*
1242260378dfSrob 	 * Limit to a decent size that works on all of our architectures.
1243260378dfSrob 	 */
1244260378dfSrob 	if (sizeof(int32_t) < n) {
1245d4b95dc4Srob 		errno = ERANGE;
1246d4b95dc4Srob 		return -1;
1247d4b95dc4Srob 	}
1248d4b95dc4Srob 	r = n + 1;
1249d4b95dc4Srob 
1250d4b95dc4Srob 	for (s = 0; n > 0; n--) {
1251696b5899Stb 		if (ober_getc(b, &u) == -1)
1252d4b95dc4Srob 			return -1;
1253d4b95dc4Srob 		s = (s << 8) | u;
1254d4b95dc4Srob 	}
1255d4b95dc4Srob 
1256d4b95dc4Srob 	if (s < 0) {
1257d4b95dc4Srob 		/* overflow */
1258d4b95dc4Srob 		errno = ERANGE;
1259d4b95dc4Srob 		return -1;
1260d4b95dc4Srob 	}
1261d4b95dc4Srob 
1262d4b95dc4Srob 	*len = s;
1263d4b95dc4Srob 	return r;
1264d4b95dc4Srob }
1265d4b95dc4Srob 
1266d4b95dc4Srob static ssize_t
ober_read_element(struct ber * ber,struct ber_element * elm)1267696b5899Stb ober_read_element(struct ber *ber, struct ber_element *elm)
1268d4b95dc4Srob {
1269d4b95dc4Srob 	long long val = 0;
1270d4b95dc4Srob 	struct ber_element *next;
1271d4b95dc4Srob 	unsigned int type;
1272d4b95dc4Srob 	int i, class, cstruct, elements = 0;
1273d4b95dc4Srob 	ssize_t len, r, totlen = 0;
1274b0a6858bSrob 	u_char c, last = 0;
1275d4b95dc4Srob 
1276d4b95dc4Srob 	if ((r = get_id(ber, &type, &class, &cstruct)) == -1)
1277d4b95dc4Srob 		return -1;
1278d4b95dc4Srob 	DPRINTF("ber read got class %d type %u, %s\n",
1279d4b95dc4Srob 	    class, type, cstruct ? "constructed" : "primitive");
1280d4b95dc4Srob 	totlen += r;
1281d4b95dc4Srob 	if ((r = get_len(ber, &len)) == -1)
1282d4b95dc4Srob 		return -1;
1283d4b95dc4Srob 	DPRINTF("ber read element size %zd\n", len);
1284d4b95dc4Srob 	totlen += r + len;
1285d4b95dc4Srob 
1286e26852ebSrob 	/* The encoding of boolean, integer, enumerated, and null values
1287e26852ebSrob 	 * must be primitive. */
1288e26852ebSrob 	if (class == BER_CLASS_UNIVERSAL)
1289e26852ebSrob 		if (type == BER_TYPE_BOOLEAN ||
1290e26852ebSrob 		    type == BER_TYPE_INTEGER ||
1291e26852ebSrob 		    type == BER_TYPE_ENUMERATED ||
1292e26852ebSrob 		    type == BER_TYPE_NULL)
1293e26852ebSrob 			if (cstruct) {
1294e26852ebSrob 				errno = EINVAL;
1295e26852ebSrob 				return -1;
1296e26852ebSrob 			}
1297e26852ebSrob 
1298d4b95dc4Srob 	/* If the total size of the element is larger than the buffer
1299d4b95dc4Srob 	 * don't bother to continue. */
1300d4b95dc4Srob 	if (len > ber->br_rend - ber->br_rptr) {
1301d4b95dc4Srob 		errno = ECANCELED;
1302d4b95dc4Srob 		return -1;
1303d4b95dc4Srob 	}
1304d4b95dc4Srob 
1305d4b95dc4Srob 	elm->be_type = type;
1306d4b95dc4Srob 	elm->be_len = len;
1307d4b95dc4Srob 	elm->be_offs = ber->br_offs;	/* element position within stream */
1308d4b95dc4Srob 	elm->be_class = class;
1309d4b95dc4Srob 
1310d4b95dc4Srob 	if (elm->be_encoding == 0) {
1311d4b95dc4Srob 		/* try to figure out the encoding via class, type and cstruct */
1312d4b95dc4Srob 		if (cstruct)
1313d4b95dc4Srob 			elm->be_encoding = BER_TYPE_SEQUENCE;
1314d4b95dc4Srob 		else if (class == BER_CLASS_UNIVERSAL)
1315d4b95dc4Srob 			elm->be_encoding = type;
1316d4b95dc4Srob 		else if (ber->br_application != NULL) {
1317d4b95dc4Srob 			/*
1318d4b95dc4Srob 			 * Ask the application to map the encoding to a
1319d4b95dc4Srob 			 * universal type. For example, a SMI IpAddress
1320d4b95dc4Srob 			 * type is defined as 4 byte OCTET STRING.
1321d4b95dc4Srob 			 */
1322d4b95dc4Srob 			elm->be_encoding = (*ber->br_application)(elm);
1323d4b95dc4Srob 		} else
1324d4b95dc4Srob 			/* last resort option */
1325d4b95dc4Srob 			elm->be_encoding = BER_TYPE_NULL;
1326d4b95dc4Srob 	}
1327d4b95dc4Srob 
1328d4b95dc4Srob 	switch (elm->be_encoding) {
1329d4b95dc4Srob 	case BER_TYPE_EOC:	/* End-Of-Content */
1330d4b95dc4Srob 		break;
1331d4b95dc4Srob 	case BER_TYPE_BOOLEAN:
1332e26852ebSrob 		if (len != 1) {
1333e26852ebSrob 			errno = EINVAL;
1334e26852ebSrob 			return -1;
1335e26852ebSrob 		}
1336d4b95dc4Srob 	case BER_TYPE_INTEGER:
1337d4b95dc4Srob 	case BER_TYPE_ENUMERATED:
133868ec4783Srob 		if (len < 1) {
133968ec4783Srob 			errno = EINVAL;
134068ec4783Srob 			return -1;
134168ec4783Srob 		}
134200f4a9fbSmartijn 		if (len > (ssize_t)sizeof(long long)) {
134300f4a9fbSmartijn 			errno = ERANGE;
1344d4b95dc4Srob 			return -1;
134500f4a9fbSmartijn 		}
1346d4b95dc4Srob 		for (i = 0; i < len; i++) {
1347696b5899Stb 			if (ober_getc(ber, &c) != 1)
1348d4b95dc4Srob 				return -1;
1349b0a6858bSrob 
1350b0a6858bSrob 			/* smallest number of contents octets only */
1351b0a6858bSrob 			if ((i == 1 && last == 0 && (c & 0x80) == 0) ||
13521f7940eeSmartijn 			    (i == 1 && last == 0xff && (c & 0x80) != 0)) {
13531f7940eeSmartijn 				errno = EINVAL;
1354b0a6858bSrob 				return -1;
13551f7940eeSmartijn 			}
1356b0a6858bSrob 
1357d4b95dc4Srob 			val <<= 8;
1358d4b95dc4Srob 			val |= c;
1359b0a6858bSrob 			last = c;
1360d4b95dc4Srob 		}
1361d4b95dc4Srob 
1362d4b95dc4Srob 		/* sign extend if MSB is set */
1363d4b95dc4Srob 		if (len < (ssize_t)sizeof(long long) &&
1364d4b95dc4Srob 		    (val >> ((len - 1) * 8) & 0x80))
1365d4b95dc4Srob 			val |= ULLONG_MAX << (len * 8);
1366d4b95dc4Srob 		elm->be_numeric = val;
1367d4b95dc4Srob 		break;
1368d4b95dc4Srob 	case BER_TYPE_BITSTRING:
1369d4b95dc4Srob 		elm->be_val = malloc(len);
1370d4b95dc4Srob 		if (elm->be_val == NULL)
1371d4b95dc4Srob 			return -1;
1372d4b95dc4Srob 		elm->be_free = 1;
1373d4b95dc4Srob 		elm->be_len = len;
1374696b5899Stb 		ober_read(ber, elm->be_val, len);
1375d4b95dc4Srob 		break;
1376d4b95dc4Srob 	case BER_TYPE_OCTETSTRING:
1377d4b95dc4Srob 	case BER_TYPE_OBJECT:
1378d4b95dc4Srob 		elm->be_val = malloc(len + 1);
1379d4b95dc4Srob 		if (elm->be_val == NULL)
1380d4b95dc4Srob 			return -1;
1381d4b95dc4Srob 		elm->be_free = 1;
1382d4b95dc4Srob 		elm->be_len = len;
1383696b5899Stb 		ober_read(ber, elm->be_val, len);
1384d4b95dc4Srob 		((u_char *)elm->be_val)[len] = '\0';
1385d4b95dc4Srob 		break;
1386d4b95dc4Srob 	case BER_TYPE_NULL:	/* no payload */
13871f7940eeSmartijn 		if (len != 0) {
13881f7940eeSmartijn 			errno = EINVAL;
1389d4b95dc4Srob 			return -1;
13901f7940eeSmartijn 		}
1391d4b95dc4Srob 		break;
1392d4b95dc4Srob 	case BER_TYPE_SEQUENCE:
1393d4b95dc4Srob 	case BER_TYPE_SET:
1394469af3a4Smartijn 		if (len > 0 && elm->be_sub == NULL) {
1395696b5899Stb 			if ((elm->be_sub = ober_get_element(0)) == NULL)
1396d4b95dc4Srob 				return -1;
1397d4b95dc4Srob 		}
1398d4b95dc4Srob 		next = elm->be_sub;
1399d4b95dc4Srob 		while (len > 0) {
1400d4b95dc4Srob 			/*
1401d4b95dc4Srob 			 * Prevent stack overflow from excessive recursion
1402696b5899Stb 			 * depth in ober_free_elements().
1403d4b95dc4Srob 			 */
1404d4b95dc4Srob 			if (elements >= BER_MAX_SEQ_ELEMENTS) {
1405d4b95dc4Srob 				errno = ERANGE;
1406d4b95dc4Srob 				return -1;
1407d4b95dc4Srob 			}
1408696b5899Stb 			r = ober_read_element(ber, next);
1409469af3a4Smartijn 			if (r == -1) {
1410469af3a4Smartijn 				/* sub-element overflows sequence/set */
1411469af3a4Smartijn 				if (errno == ECANCELED)
1412469af3a4Smartijn 					errno = EINVAL;
1413d4b95dc4Srob 				return -1;
1414469af3a4Smartijn 			}
1415469af3a4Smartijn 			if (r > len) {
1416469af3a4Smartijn 				errno = EINVAL;
1417469af3a4Smartijn 				return -1;
1418469af3a4Smartijn 			}
1419d4b95dc4Srob 			elements++;
1420d4b95dc4Srob 			len -= r;
1421d4b95dc4Srob 			if (len > 0 && next->be_next == NULL) {
1422469af3a4Smartijn 				next->be_next = ober_get_element(0);
1423469af3a4Smartijn 				if (next->be_next == NULL)
1424d4b95dc4Srob 					return -1;
1425d4b95dc4Srob 			}
1426d4b95dc4Srob 			next = next->be_next;
1427d4b95dc4Srob 		}
1428d4b95dc4Srob 		break;
1429d4b95dc4Srob 	}
1430d4b95dc4Srob 	return totlen;
1431d4b95dc4Srob }
1432d4b95dc4Srob 
1433d4b95dc4Srob static ssize_t
ober_getc(struct ber * b,u_char * c)1434696b5899Stb ober_getc(struct ber *b, u_char *c)
1435d4b95dc4Srob {
1436696b5899Stb 	return ober_read(b, c, 1);
1437d4b95dc4Srob }
1438d4b95dc4Srob 
1439d4b95dc4Srob static ssize_t
ober_read(struct ber * ber,void * buf,size_t len)1440696b5899Stb ober_read(struct ber *ber, void *buf, size_t len)
1441d4b95dc4Srob {
1442d4b95dc4Srob 	size_t	sz;
1443d4b95dc4Srob 
14441f7940eeSmartijn 	if (ber->br_rbuf == NULL) {
14451f7940eeSmartijn 		errno = ENOBUFS;
1446d4b95dc4Srob 		return -1;
14471f7940eeSmartijn 	}
1448d4b95dc4Srob 
1449d4b95dc4Srob 	sz = ber->br_rend - ber->br_rptr;
1450d4b95dc4Srob 	if (len > sz) {
1451d4b95dc4Srob 		errno = ECANCELED;
1452d4b95dc4Srob 		return -1;	/* parser wants more data than available */
1453d4b95dc4Srob 	}
1454d4b95dc4Srob 
1455d4b95dc4Srob 	bcopy(ber->br_rptr, buf, len);
1456d4b95dc4Srob 	ber->br_rptr += len;
1457d4b95dc4Srob 	ber->br_offs += len;
1458d4b95dc4Srob 
1459d4b95dc4Srob 	return len;
1460d4b95dc4Srob }
1461