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