xref: /freebsd/contrib/bsnmp/lib/asn1.c (revision 6af83ee0d2941d18880b6aaa2b4facd1d30c6106)
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 
42 static void asn_error_func(const struct asn_buf *, const char *, ...);
43 
44 void (*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  */
52 enum asn_err
53 asn_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  */
105 static u_int
106 asn_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  */
142 enum asn_err
143 asn_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)
180 enum asn_err
181 asn_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 }
192 enum asn_err
193 asn_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  */
224 static enum asn_err
225 asn_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  */
270 static enum asn_err
271 asn_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  */
318 static enum asn_err
319 asn_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  */
355 static int
356 asn_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  */
388 enum asn_err
389 asn_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 
405 enum asn_err
406 asn_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 
422 enum asn_err
423 asn_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  */
437 enum asn_err
438 asn_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 
461 enum asn_err
462 asn_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 
477 enum asn_err
478 asn_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  */
498 enum asn_err
499 asn_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 
514 enum asn_err
515 asn_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 
530 enum asn_err
531 asn_put_null(struct asn_buf *b)
532 {
533 	return (asn_put_header(b, ASN_TYPE_NULL, 0));
534 }
535 
536 enum asn_err
537 asn_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  */
547 enum asn_err
548 asn_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 
602 enum asn_err
603 asn_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 
618 enum asn_err
619 asn_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  */
709 enum asn_err
710 asn_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  */
733 enum asn_err
734 asn_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 
758 enum asn_err
759 asn_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 
774 enum asn_err
775 asn_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  */
797 enum asn_err
798 asn_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 
816 enum asn_err
817 asn_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  */
828 enum asn_err
829 asn_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 
834 enum asn_err
835 asn_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  */
845 enum asn_err
846 asn_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 
861 enum asn_err
862 asn_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  */
873 void
874 asn_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  */
888 void
889 asn_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  */
899 enum asn_err
900 asn_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  */
916 int
917 asn_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  */
937 int
938 asn_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  */
954 char *
955 asn_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  */
974 char *
975 asn_oid2str(const struct asn_oid *oid)
976 {
977 	static char str[ASN_OIDSTRLEN];
978 
979 	return (asn_oid2str_r(oid, str));
980 }
981 
982 
983 static void
984 asn_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