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