xref: /freebsd/contrib/bsnmp/lib/asn1.c (revision 6b3455a7665208c366849f0b2b3bc916fb97516e)
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 
46 static void asn_error_func(const struct asn_buf *, const char *, ...);
47 
48 void (*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  */
56 enum asn_err
57 asn_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  */
109 static u_int
110 asn_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  */
146 enum asn_err
147 asn_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)
184 enum asn_err
185 asn_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 }
196 enum asn_err
197 asn_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  */
228 static enum asn_err
229 asn_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  */
274 static enum asn_err
275 asn_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  */
322 static enum asn_err
323 asn_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  */
359 static int
360 asn_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  */
392 enum asn_err
393 asn_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 
409 enum asn_err
410 asn_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 
426 enum asn_err
427 asn_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  */
441 enum asn_err
442 asn_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 
465 enum asn_err
466 asn_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 
481 enum asn_err
482 asn_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  */
502 enum asn_err
503 asn_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 
518 enum asn_err
519 asn_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 
534 enum asn_err
535 asn_put_null(struct asn_buf *b)
536 {
537 	return (asn_put_header(b, ASN_TYPE_NULL, 0));
538 }
539 
540 enum asn_err
541 asn_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  */
551 enum asn_err
552 asn_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 
606 enum asn_err
607 asn_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 
622 enum asn_err
623 asn_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  */
713 enum asn_err
714 asn_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  */
737 enum asn_err
738 asn_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 
762 enum asn_err
763 asn_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 
778 enum asn_err
779 asn_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  */
801 enum asn_err
802 asn_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 
820 enum asn_err
821 asn_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  */
832 enum asn_err
833 asn_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 
838 enum asn_err
839 asn_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  */
849 enum asn_err
850 asn_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 
865 enum asn_err
866 asn_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  */
877 void
878 asn_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  */
892 void
893 asn_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  */
903 enum asn_err
904 asn_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  */
920 int
921 asn_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  */
941 int
942 asn_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  */
958 char *
959 asn_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  */
978 char *
979 asn_oid2str(const struct asn_oid *oid)
980 {
981 	static char str[ASN_OIDSTRLEN];
982 
983 	return (asn_oid2str_r(oid, str));
984 }
985 
986 
987 static void
988 asn_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