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