asn1.c revision 133211
1/*
2 * Copyright (c) 2001-2003
3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4 *	All rights reserved.
5 *
6 * Author: Harti Brandt <harti@freebsd.org>
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * $Begemot: bsnmp/lib/asn1.c,v 1.28 2004/08/06 08:46:49 brandt Exp $
30 *
31 * ASN.1 for SNMP.
32 */
33#include <sys/types.h>
34#include <stdio.h>
35#include <stdlib.h>
36#include <stdarg.h>
37#include <string.h>
38#include <stdint.h>
39#include <assert.h>
40#include "asn1.h"
41
42static void asn_error_func(const struct asn_buf *, const char *, ...);
43
44void (*asn_error)(const struct asn_buf *, const char *, ...) = asn_error_func;
45
46/*
47 * Read the next header. This reads the tag (note, that only single
48 * byte tags are supported for now) and the length field. The length field
49 * is restricted to a 32-bit value.
50 * All errors of this function stop the decoding.
51 */
52enum asn_err
53asn_get_header(struct asn_buf *b, u_char *type, asn_len_t *len)
54{
55	u_int length;
56
57	if (b->asn_len == 0) {
58		asn_error(b, "no identifier for header");
59		return (ASN_ERR_EOBUF);
60	}
61	*type = *b->asn_cptr;
62	if ((*type & ASN_TYPE_MASK) > 0x30) {
63		asn_error(b, "types > 0x30 not supported (%u)",
64		    *type & ASN_TYPE_MASK);
65		return (ASN_ERR_FAILED);
66	}
67	b->asn_cptr++;
68	b->asn_len--;
69	if (b->asn_len == 0) {
70		asn_error(b, "no length field");
71		return (ASN_ERR_EOBUF);
72	}
73	if (*b->asn_cptr & 0x80) {
74		length = *b->asn_cptr++ & 0x7f;
75		b->asn_len--;
76		if (length == 0) {
77			asn_error(b, "indefinite length not supported");
78			return (ASN_ERR_FAILED);
79		}
80		if (length > ASN_MAXLENLEN) {
81			asn_error(b, "long length too long (%u)", length);
82			return (ASN_ERR_FAILED);
83		}
84		if (length > b->asn_len) {
85			asn_error(b, "long length truncated");
86			return (ASN_ERR_EOBUF);
87		}
88		*len = 0;
89		while (length--) {
90			*len = (*len << 8) | *b->asn_cptr++;
91			b->asn_len--;
92		}
93	} else {
94		*len = *b->asn_cptr++;
95		b->asn_len--;
96	}
97	return (ASN_ERR_OK);
98}
99
100/*
101 * Write a length field (restricted to values < 2^32-1) and return the
102 * number of bytes this field takes. If ptr is NULL, the length is computed
103 * but nothing is written. If the length would be too large return 0.
104 */
105static u_int
106asn_put_len(u_char *ptr, asn_len_t len)
107{
108	u_int lenlen, lenlen1;
109	asn_len_t tmp;
110
111	if (len > ASN_MAXLEN) {
112		asn_error(NULL, "encoding length too long: (%u)", len);
113		return (0);
114	}
115
116	if (len <= 127) {
117		if (ptr)
118			*ptr++ = (u_char)len;
119		return (1);
120	} else {
121		lenlen = 0;
122		/* compute number of bytes for value (is at least 1) */
123		for (tmp = len; tmp != 0; tmp >>= 8)
124			lenlen++;
125		if (ptr != NULL) {
126			*ptr++ = (u_char)lenlen | 0x80;
127			lenlen1 = lenlen;
128			while (lenlen1-- > 0) {
129				ptr[lenlen1] = len & 0xff;
130				len >>= 8;
131			}
132		}
133		return (lenlen + 1);
134	}
135}
136
137/*
138 * Write a header (tag and length fields).
139 * Tags are restricted to one byte tags (value <= 0x30) and the
140 * lenght field to 16-bit. All errors stop the encoding.
141 */
142enum asn_err
143asn_put_header(struct asn_buf *b, u_char type, asn_len_t len)
144{
145	u_int lenlen;
146
147	/* tag field */
148	if ((type & ASN_TYPE_MASK) > 0x30) {
149		asn_error(NULL, "types > 0x30 not supported (%u)",
150		    type & ASN_TYPE_MASK);
151		return (ASN_ERR_FAILED);
152	}
153	if (b->asn_len == 0)
154		return (ASN_ERR_EOBUF);
155
156	*b->asn_ptr++ = type;
157	b->asn_len--;
158
159	/* length field */
160	if ((lenlen = asn_put_len(NULL, len)) == 0)
161		return (ASN_ERR_FAILED);
162	if (b->asn_len < lenlen)
163		return (ASN_ERR_EOBUF);
164
165	(void)asn_put_len(b->asn_ptr, len);
166	b->asn_ptr += lenlen;
167	b->asn_len -= lenlen;
168	return (ASN_ERR_OK);
169}
170
171
172/*
173 * This constructs a temporary sequence header with space for the maximum
174 * length field (three byte). Set the pointer that ptr points to to the
175 * start of the encoded header. This is used for a later call to
176 * asn_commit_header which will fix-up the length field and move the
177 * value if needed. All errors should stop the encoding.
178 */
179#define	TEMP_LEN (1 + ASN_MAXLENLEN + 1)
180enum asn_err
181asn_put_temp_header(struct asn_buf *b, u_char type, u_char **ptr)
182{
183	int ret;
184
185	if (b->asn_len < TEMP_LEN)
186		return (ASN_ERR_EOBUF);
187	*ptr = b->asn_ptr;
188	if ((ret = asn_put_header(b, type, ASN_MAXLEN)) == ASN_ERR_OK)
189		assert(b->asn_ptr == *ptr + TEMP_LEN);
190	return (ret);
191}
192enum asn_err
193asn_commit_header(struct asn_buf *b, u_char *ptr)
194{
195	asn_len_t len;
196	u_int lenlen, shift;
197
198	/* compute length of encoded value without header */
199	len = b->asn_ptr - (ptr + TEMP_LEN);
200
201	/* insert length. may not fail. */
202	lenlen = asn_put_len(ptr + 1, len);
203	if (lenlen > TEMP_LEN - 1)
204		return (ASN_ERR_FAILED);
205
206	if (lenlen < TEMP_LEN - 1) {
207		/* shift value down */
208		shift = (TEMP_LEN - 1) - lenlen;
209		memmove(ptr + 1 + lenlen, ptr + TEMP_LEN, len);
210		b->asn_ptr -= shift;
211		b->asn_len += shift;
212	}
213	return (ASN_ERR_OK);
214}
215#undef TEMP_LEN
216
217/*
218 * BER integer. This may be used to get a signed 64 bit integer at maximum.
219 * The maximum length should be checked by the caller. This cannot overflow
220 * if the caller ensures that len is at maximum 8.
221 *
222 * <bytes>
223 */
224static enum asn_err
225asn_get_real_integer(struct asn_buf *b, asn_len_t len, int64_t *vp)
226{
227	uint64_t val;
228	int neg = 0;
229	enum asn_err err;
230
231	if (b->asn_len < len) {
232		asn_error(b, "truncated integer");
233		return (ASN_ERR_EOBUF);
234	}
235	if (len == 0) {
236		asn_error(b, "zero-length integer");
237		*vp = 0;
238		return (ASN_ERR_BADLEN);
239	}
240	err = ASN_ERR_OK;
241	if (len > 8)
242		err = ASN_ERR_RANGE;
243	else if (len > 1 &&
244	    ((*b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) ||
245	    (*b->asn_cptr == 0xff && (b->asn_cptr[1] & 0x80) == 0x80))) {
246		asn_error(b, "non-minimal integer");
247		err = ASN_ERR_BADLEN;
248	}
249
250	if (*b->asn_cptr & 0x80)
251		neg = 1;
252	val = 0;
253	while (len--) {
254		val <<= 8;
255		val |= neg ? (u_char)~*b->asn_cptr : *b->asn_cptr;
256		b->asn_len--;
257		b->asn_cptr++;
258	}
259	if (neg) {
260		*vp = -(int64_t)val - 1;
261	} else
262		*vp = (int64_t)val;
263	return (err);
264}
265
266/*
267 * Write a signed integer with the given type. The caller has to ensure
268 * that the actual value is ok for this type.
269 */
270static enum asn_err
271asn_put_real_integer(struct asn_buf *b, u_char type, int64_t ival)
272{
273	int i, neg = 0;
274# define OCTETS 8
275	u_char buf[OCTETS];
276	uint64_t val;
277	enum asn_err ret;
278
279	if (ival < 0) {
280		/* this may fail if |INT64_MIN| > |INT64_MAX| and
281		 * the value is between * INT64_MIN <= ival < -(INT64_MAX+1) */
282		val = (uint64_t)-(ival + 1);
283		neg = 1;
284	} else
285		val = (uint64_t)ival;
286
287	/* split the value into octets */
288	for (i = OCTETS - 1; i >= 0; i--) {
289		buf[i] = val & 0xff;
290		if (neg)
291			buf[i] = ~buf[i];
292		val >>= 8;
293	}
294	/* no leading 9 zeroes or ones */
295	for (i = 0; i < OCTETS - 1; i++)
296		if (!((buf[i] == 0xff && (buf[i + 1] & 0x80) != 0) ||
297		    (buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0)))
298			break;
299	if ((ret = asn_put_header(b, type, OCTETS - i)))
300		return (ret);
301	if (OCTETS - (u_int)i > b->asn_len)
302		return (ASN_ERR_EOBUF);
303
304	while (i < OCTETS) {
305		*b->asn_ptr++ = buf[i++];
306		b->asn_len--;
307	}
308	return (ASN_ERR_OK);
309# undef OCTETS
310}
311
312
313/*
314 * The same for unsigned 64-bitters. Here we have the problem, that overflow
315 * can happen, because the value maybe 9 bytes long. In this case the
316 * first byte must be 0.
317 */
318static enum asn_err
319asn_get_real_unsigned(struct asn_buf *b, asn_len_t len, uint64_t *vp)
320{
321	enum asn_err err;
322
323	if (b->asn_len < len) {
324		asn_error(b, "truncated integer");
325		return (ASN_ERR_EOBUF);
326	}
327	if (len == 0) {
328		asn_error(b, "zero-length integer");
329		*vp = 0;
330		return (ASN_ERR_BADLEN);
331	}
332	err = ASN_ERR_OK;
333	*vp = 0;
334	if ((*b->asn_cptr & 0x80) || (len == 9 && *b->asn_cptr != 0)) {
335		/* negative integer or too larger */
336		*vp = 0xffffffffffffffffULL;
337		err = ASN_ERR_RANGE;
338	} else if (len > 1 &&
339	    *b->asn_cptr == 0x00 && (b->asn_cptr[1] & 0x80) == 0) {
340		asn_error(b, "non-minimal unsigned");
341		err = ASN_ERR_BADLEN;
342	}
343
344	while (len--) {
345		*vp = (*vp << 8) | *b->asn_cptr++;
346		b->asn_len--;
347	}
348	return (err);
349}
350
351
352/*
353 * Values with the msb on need 9 octets.
354 */
355static int
356asn_put_real_unsigned(struct asn_buf *b, u_char type, uint64_t val)
357{
358	int i;
359# define OCTETS 9
360	u_char buf[OCTETS];
361	enum asn_err ret;
362
363	/* split the value into octets */
364	for (i = OCTETS - 1; i >= 0; i--) {
365		buf[i] = val & 0xff;
366		val >>= 8;
367	}
368	/* no leading 9 zeroes */
369	for (i = 0; i < OCTETS - 1; i++)
370		if (!(buf[i] == 0x00 && (buf[i + 1] & 0x80) == 0))
371			break;
372	if ((ret = asn_put_header(b, type, OCTETS - i)))
373		return (ret);
374	if (OCTETS - (u_int)i > b->asn_len)
375		return (ASN_ERR_EOBUF);
376
377	while (i < OCTETS) {
378		*b->asn_ptr++ = buf[i++];
379		b->asn_len--;
380	}
381#undef OCTETS
382	return (ASN_ERR_OK);
383}
384
385/*
386 * The ASN.1 INTEGER type is restricted to 32-bit signed by the SMI.
387 */
388enum asn_err
389asn_get_integer_raw(struct asn_buf *b, asn_len_t len, int32_t *vp)
390{
391	int64_t val;
392	enum asn_err ret;
393
394	if ((ret = asn_get_real_integer(b, len, &val)) == ASN_ERR_OK) {
395		if (len > 4)
396			ret = ASN_ERR_BADLEN;
397		else if (val > INT32_MAX || val < INT32_MIN)
398			/* may not happen */
399			ret = ASN_ERR_RANGE;
400		*vp = (int32_t)val;
401	}
402	return (ret);
403}
404
405enum asn_err
406asn_get_integer(struct asn_buf *b, int32_t *vp)
407{
408	asn_len_t len;
409	u_char type;
410	enum asn_err err;
411
412	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
413		return (err);
414	if (type != ASN_TYPE_INTEGER) {
415		asn_error(b, "bad type for integer (%u)", type);
416		return (ASN_ERR_TAG);
417	}
418
419	return (asn_get_integer_raw(b, len, vp));
420}
421
422enum asn_err
423asn_put_integer(struct asn_buf *b, int32_t val)
424{
425	return (asn_put_real_integer(b, ASN_TYPE_INTEGER, val));
426}
427
428/*
429 * OCTETSTRING
430 *
431 * <0x04> <len> <data ...>
432 *
433 * Get an octetstring. noctets must point to the buffer size and on
434 * return will contain the size of the octetstring, regardless of the
435 * buffer size.
436 */
437enum asn_err
438asn_get_octetstring_raw(struct asn_buf *b, asn_len_t len, u_char *octets,
439    u_int *noctets)
440{
441	enum asn_err err = ASN_ERR_OK;
442
443	if (*noctets < len) {
444		asn_error(b, "octetstring truncated");
445		err = ASN_ERR_RANGE;
446	}
447	if (b->asn_len < len) {
448		asn_error(b, "truncatet octetstring");
449		return (ASN_ERR_EOBUF);
450	}
451	if (*noctets < len)
452		memcpy(octets, b->asn_cptr, *noctets);
453	else
454		memcpy(octets, b->asn_cptr, len);
455	*noctets = len;
456	b->asn_cptr += len;
457	b->asn_len -= len;
458	return (err);
459}
460
461enum asn_err
462asn_get_octetstring(struct asn_buf *b, u_char *octets, u_int *noctets)
463{
464	enum asn_err err;
465	u_char type;
466	asn_len_t len;
467
468	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
469		return (err);
470	if (type != ASN_TYPE_OCTETSTRING) {
471		asn_error(b, "bad type for octetstring (%u)", type);
472		return (ASN_ERR_TAG);
473	}
474	return (asn_get_octetstring_raw(b, len, octets, noctets));
475}
476
477enum asn_err
478asn_put_octetstring(struct asn_buf *b, const u_char *octets, u_int noctets)
479{
480	enum asn_err ret;
481
482	if ((ret = asn_put_header(b, ASN_TYPE_OCTETSTRING, noctets)) != ASN_ERR_OK)
483		return (ret);
484	if (b->asn_len < noctets)
485		return (ASN_ERR_EOBUF);
486
487	memcpy(b->asn_ptr, octets, noctets);
488	b->asn_ptr += noctets;
489	b->asn_len -= noctets;
490	return (ASN_ERR_OK);
491}
492
493/*
494 * NULL
495 *
496 * <0x05> <0x00>
497 */
498enum asn_err
499asn_get_null_raw(struct asn_buf *b, asn_len_t len)
500{
501	if (len != 0) {
502		if (b->asn_len < len) {
503			asn_error(b, "truncated NULL");
504			return (ASN_ERR_EOBUF);
505		}
506		asn_error(b, "bad length for NULL (%u)", len);
507		b->asn_len -= len;
508		b->asn_ptr += len;
509		return (ASN_ERR_BADLEN);
510	}
511	return (ASN_ERR_OK);
512}
513
514enum asn_err
515asn_get_null(struct asn_buf *b)
516{
517	u_char type;
518	asn_len_t len;
519	enum asn_err err;
520
521	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
522		return (err);
523	if (type != ASN_TYPE_NULL) {
524		asn_error(b, "bad type for NULL (%u)", type);
525		return (ASN_ERR_TAG);
526	}
527	return (asn_get_null_raw(b, len));
528}
529
530enum asn_err
531asn_put_null(struct asn_buf *b)
532{
533	return (asn_put_header(b, ASN_TYPE_NULL, 0));
534}
535
536enum asn_err
537asn_put_exception(struct asn_buf *b, u_int except)
538{
539	return (asn_put_header(b, ASN_CLASS_CONTEXT | except, 0));
540}
541
542/*
543 * OBJID
544 *
545 * <0x06> <len> <subid...>
546 */
547enum asn_err
548asn_get_objid_raw(struct asn_buf *b, asn_len_t len, struct asn_oid *oid)
549{
550	asn_subid_t subid;
551	enum asn_err err;
552
553	if (b->asn_len < len) {
554		asn_error(b, "truncated OBJID");
555		return (ASN_ERR_EOBUF);
556	}
557	oid->len = 0;
558	if (len == 0) {
559		asn_error(b, "short OBJID");
560		oid->subs[oid->len++] = 0;
561		oid->subs[oid->len++] = 0;
562		return (ASN_ERR_BADLEN);
563	}
564	err = ASN_ERR_OK;
565	while (len != 0) {
566		if (oid->len == ASN_MAXOIDLEN) {
567			asn_error(b, "OID too long (%u)", oid->len);
568			b->asn_cptr += len;
569			b->asn_len -= len;
570			return (ASN_ERR_BADLEN);
571		}
572		subid = 0;
573		do {
574			if (len == 0) {
575				asn_error(b, "unterminated subid");
576				return (ASN_ERR_EOBUF);
577			}
578			if (subid > (ASN_MAXID >> 7)) {
579				asn_error(b, "OBID subid too larger");
580				err = ASN_ERR_RANGE;
581			}
582			subid = (subid << 7) | (*b->asn_cptr & 0x7f);
583			len--;
584			b->asn_len--;
585		} while (*b->asn_cptr++ & 0x80);
586		if (oid->len == 0) {
587			if (subid < 80) {
588				oid->subs[oid->len++] = subid / 40;
589				oid->subs[oid->len++] = subid % 40;
590			} else {
591				oid->subs[oid->len++] = 2;
592				oid->subs[oid->len++] = subid - 80;
593			}
594		} else {
595			oid->subs[oid->len++] = subid;
596		}
597	}
598	return (err);
599
600}
601
602enum asn_err
603asn_get_objid(struct asn_buf *b, struct asn_oid *oid)
604{
605	u_char type;
606	asn_len_t len;
607	enum asn_err err;
608
609	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
610		return (err);
611	if (type != ASN_TYPE_OBJID) {
612		asn_error(b, "bad type for OBJID (%u)", type);
613		return (ASN_ERR_TAG);
614	}
615	return (asn_get_objid_raw(b, len, oid));
616}
617
618enum asn_err
619asn_put_objid(struct asn_buf *b, const struct asn_oid *oid)
620{
621	asn_subid_t first, sub;
622	enum asn_err err, err1;
623	u_int i, oidlen;
624	asn_len_t len;
625
626	err = ASN_ERR_OK;
627	if (oid->len == 0) {
628		/* illegal */
629		asn_error(NULL, "short oid");
630		err = ASN_ERR_RANGE;
631		first = 0;
632		oidlen = 2;
633	} else if (oid->len == 1) {
634		/* illegal */
635		asn_error(b, "short oid");
636		if (oid->subs[0] > 2)
637			asn_error(NULL, "oid[0] too large (%u)", oid->subs[0]);
638		err = ASN_ERR_RANGE;
639		first = oid->subs[0] * 40;
640		oidlen = 2;
641	} else {
642		if (oid->len > ASN_MAXOIDLEN) {
643			asn_error(NULL, "oid too long %u", oid->len);
644			err = ASN_ERR_RANGE;
645		}
646		if (oid->subs[0] > 2 ||
647		    (oid->subs[0] < 2 && oid->subs[0] >= 40)) {
648			asn_error(NULL, "oid out of range (%u,%u)",
649			    oid->subs[0], oid->subs[1]);
650			err = ASN_ERR_RANGE;
651		}
652		first = 40 * oid->subs[0] + oid->subs[1];
653		oidlen = oid->len;
654	}
655	len = 0;
656	for (i = 1; i < oidlen; i++) {
657		sub = (i == 1) ? first : oid->subs[i];
658		if (sub > ASN_MAXID) {
659			asn_error(NULL, "oid subid too large");
660			err = ASN_ERR_RANGE;
661		}
662		len += (sub <= 0x7f) ? 1
663		    : (sub <= 0x3fff) ? 2
664		    : (sub <= 0x1fffff) ? 3
665		    : (sub <= 0xfffffff) ? 4
666		    : 5;
667	}
668	if ((err1 = asn_put_header(b, ASN_TYPE_OBJID, len)) != ASN_ERR_OK)
669		return (err1);
670	if (b->asn_len < len)
671		return (ASN_ERR_EOBUF);
672
673	for (i = 1; i < oidlen; i++) {
674		sub = (i == 1) ? first : oid->subs[i];
675		if (sub <= 0x7f) {
676			*b->asn_ptr++ = sub;
677			b->asn_len--;
678		} else if (sub <= 0x3fff) {
679			*b->asn_ptr++ = (sub >> 7) | 0x80;
680			*b->asn_ptr++ = sub & 0x7f;
681			b->asn_len -= 2;
682		} else if (sub <= 0x1fffff) {
683			*b->asn_ptr++ = (sub >> 14) | 0x80;
684			*b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80;
685			*b->asn_ptr++ = sub & 0x7f;
686			b->asn_len -= 3;
687		} else if (sub <= 0xfffffff) {
688			*b->asn_ptr++ = (sub >> 21) | 0x80;
689			*b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80;
690			*b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80;
691			*b->asn_ptr++ = sub & 0x7f;
692			b->asn_len -= 4;
693		} else {
694			*b->asn_ptr++ = (sub >> 28) | 0x80;
695			*b->asn_ptr++ = ((sub >> 21) & 0x7f) | 0x80;
696			*b->asn_ptr++ = ((sub >> 14) & 0x7f) | 0x80;
697			*b->asn_ptr++ = ((sub >> 7) & 0x7f) | 0x80;
698			*b->asn_ptr++ = sub & 0x7f;
699			b->asn_len -= 5;
700		}
701	}
702	return (err);
703}
704/*
705 * SEQUENCE header
706 *
707 * <0x10|0x20> <len> <data...>
708 */
709enum asn_err
710asn_get_sequence(struct asn_buf *b, asn_len_t *len)
711{
712	u_char type;
713	enum asn_err err;
714
715	if ((err = asn_get_header(b, &type, len)) != ASN_ERR_OK)
716		return (err);
717	if (type != (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED)) {
718		asn_error(b, "bad sequence type %u", type);
719		return (ASN_ERR_TAG);
720	}
721	if (*len > b->asn_len) {
722		asn_error(b, "truncated sequence");
723		return (ASN_ERR_EOBUF);
724	}
725	return (ASN_ERR_OK);
726}
727
728/*
729 * Application types
730 *
731 * 0x40 4 MSB 2MSB 2LSB LSB
732 */
733enum asn_err
734asn_get_ipaddress_raw(struct asn_buf *b, asn_len_t len, u_char *addr)
735{
736	u_int i;
737
738	if (b->asn_len < len) {
739		asn_error(b, "truncated ip-address");
740		return (ASN_ERR_EOBUF);
741	}
742	if (len < 4) {
743		asn_error(b, "short length for ip-Address %u", len);
744		for (i = 0; i < len; i++)
745			*addr++ = *b->asn_cptr++;
746		while (i++ < len)
747			*addr++ = 0;
748		b->asn_len -= len;
749		return (ASN_ERR_BADLEN);
750	}
751	for (i = 0; i < 4; i++)
752		*addr++ = *b->asn_cptr++;
753	b->asn_cptr += len - 4;
754	b->asn_len -= len;
755	return (ASN_ERR_OK);
756}
757
758enum asn_err
759asn_get_ipaddress(struct asn_buf *b, u_char *addr)
760{
761	u_char type;
762	asn_len_t len;
763	enum asn_err err;
764
765	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
766		return (err);
767	if (type != (ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS)) {
768		asn_error(b, "bad type for ip-address %u", type);
769		return (ASN_ERR_TAG);
770	}
771	return (asn_get_ipaddress_raw(b, len, addr));
772}
773
774enum asn_err
775asn_put_ipaddress(struct asn_buf *b, const u_char *addr)
776{
777	enum asn_err err;
778
779	if ((err = asn_put_header(b, ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS,
780	    4)) != ASN_ERR_OK)
781		return (err);
782	if (b->asn_len < 4)
783		return (ASN_ERR_EOBUF);
784
785	memcpy(b->asn_ptr, addr, 4);
786	b->asn_ptr += 4;
787	b->asn_len -= 4;
788	return (ASN_ERR_OK);
789}
790
791
792/*
793 * UNSIGNED32
794 *
795 * 0x42|0x41 <len> ...
796 */
797enum asn_err
798asn_get_uint32_raw(struct asn_buf *b, asn_len_t len, uint32_t *vp)
799{
800	uint64_t v;
801	enum asn_err err;
802
803	if ((err = asn_get_real_unsigned(b, len, &v)) == ASN_ERR_OK) {
804		if (len > 5) {
805			asn_error(b, "uint32 too long %u", len);
806			err = ASN_ERR_BADLEN;
807		} else if (v > UINT32_MAX) {
808			asn_error(b, "uint32 too large %llu", v);
809			err = ASN_ERR_RANGE;
810		}
811		*vp = (uint32_t)v;
812	}
813	return (err);
814}
815
816enum asn_err
817asn_put_uint32(struct asn_buf *b, u_char type, uint32_t val)
818{
819	uint64_t v = val;
820
821	return (asn_put_real_unsigned(b, ASN_CLASS_APPLICATION|type, v));
822}
823
824/*
825 * COUNTER64
826 * 0x46 <len> ...
827 */
828enum asn_err
829asn_get_counter64_raw(struct asn_buf *b, asn_len_t len, uint64_t *vp)
830{
831	return (asn_get_real_unsigned(b, len, vp));
832}
833
834enum asn_err
835asn_put_counter64(struct asn_buf *b, uint64_t val)
836{
837	return (asn_put_real_unsigned(b,
838	    ASN_CLASS_APPLICATION | ASN_APP_COUNTER64, val));
839}
840
841/*
842 * TimeTicks
843 * 0x43 <len> ...
844 */
845enum asn_err
846asn_get_timeticks(struct asn_buf *b, uint32_t *vp)
847{
848	asn_len_t len;
849	u_char type;
850	enum asn_err err;
851
852	if ((err = asn_get_header(b, &type, &len)) != ASN_ERR_OK)
853		return (err);
854	if (type != (ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS)) {
855		asn_error(b, "bad type for timeticks %u", type);
856		return (ASN_ERR_TAG);
857	}
858	return (asn_get_uint32_raw(b, len, vp));
859}
860
861enum asn_err
862asn_put_timeticks(struct asn_buf *b, uint32_t val)
863{
864	uint64_t v = val;
865
866	return (asn_put_real_unsigned(b,
867	    ASN_CLASS_APPLICATION | ASN_APP_TIMETICKS, v));
868}
869
870/*
871 * Construct a new OID by taking a range of sub ids of the original oid.
872 */
873void
874asn_slice_oid(struct asn_oid *dest, const struct asn_oid *src,
875    u_int from, u_int to)
876{
877	if (from >= to) {
878		dest->len = 0;
879		return;
880	}
881	dest->len = to - from;
882	memcpy(dest->subs, &src->subs[from], dest->len * sizeof(dest->subs[0]));
883}
884
885/*
886 * Append from to to
887 */
888void
889asn_append_oid(struct asn_oid *to, const struct asn_oid *from)
890{
891	memcpy(&to->subs[to->len], &from->subs[0],
892	    from->len * sizeof(from->subs[0]));
893	to->len += from->len;
894}
895
896/*
897 * Skip a value
898 */
899enum asn_err
900asn_skip(struct asn_buf *b, asn_len_t len)
901{
902	if (b->asn_len < len)
903		return (ASN_ERR_EOBUF);
904	b->asn_cptr += len;
905	b->asn_len -= len;
906	return (ASN_ERR_OK);
907}
908
909/*
910 * Compare two OIDs.
911 *
912 * o1 < o2 : -1
913 * o1 > o2 : +1
914 * o1 = o2 :  0
915 */
916int
917asn_compare_oid(const struct asn_oid *o1, const struct asn_oid *o2)
918{
919	u_long i;
920
921	for (i = 0; i < o1->len && i < o2->len; i++) {
922		if (o1->subs[i] < o2->subs[i])
923			return (-1);
924		if (o1->subs[i] > o2->subs[i])
925			return (+1);
926	}
927	if (o1->len < o2->len)
928		return (-1);
929	if (o1->len > o2->len)
930		return (+1);
931	return (0);
932}
933
934/*
935 * Check whether an OID is a sub-string of another OID.
936 */
937int
938asn_is_suboid(const struct asn_oid *o1, const struct asn_oid *o2)
939{
940	u_long i;
941
942	for (i = 0; i < o1->len; i++)
943		if (i >= o2->len || o1->subs[i] != o2->subs[i])
944			return (0);
945	return (1);
946}
947
948/*
949 * Put a string representation of an oid into a user buffer. This buffer
950 * is assumed to be at least ASN_OIDSTRLEN characters long.
951 *
952 * sprintf is assumed not to fail here.
953 */
954char *
955asn_oid2str_r(const struct asn_oid *oid, char *buf)
956{
957	u_int len, i;
958	char *ptr;
959
960	if ((len = oid->len) > ASN_MAXOIDLEN)
961		len = ASN_MAXOIDLEN;
962	buf[0] = '\0';
963	for (i = 0, ptr = buf; i < len; i++) {
964		if (i > 0)
965			*ptr++ = '.';
966		ptr += sprintf(ptr, "%u", oid->subs[i]);
967	}
968	return (buf);
969}
970
971/*
972 * Make a string from an OID in a private buffer.
973 */
974char *
975asn_oid2str(const struct asn_oid *oid)
976{
977	static char str[ASN_OIDSTRLEN];
978
979	return (asn_oid2str_r(oid, str));
980}
981
982
983static void
984asn_error_func(const struct asn_buf *b, const char *err, ...)
985{
986	va_list ap;
987	u_long i;
988
989	fprintf(stderr, "ASN.1: ");
990	va_start(ap, err);
991	vfprintf(stderr, err, ap);
992	va_end(ap);
993
994	if (b != NULL) {
995		fprintf(stderr, " at");
996		for (i = 0; b->asn_len > i; i++)
997			fprintf(stderr, " %02x", b->asn_cptr[i]);
998	}
999	fprintf(stderr, "\n");
1000}
1001