]> git.ipfire.org Git - thirdparty/squid.git/blame - snmplib/asn1.c
bounds bug
[thirdparty/squid.git] / snmplib / asn1.c
CommitLineData
627f6d02 1/*
2 * Abstract Syntax Notation One, ASN.1
3 * As defined in ISO/IS 8824 and ISO/IS 8825
4 * This implements a subset of the above International Standards that
5 * is sufficient to implement SNMP.
6 *
7 * Encodes abstract data types into a machine independent stream of bytes.
8 *
9 */
85269fdf 10/***************************************************************************
11 *
12 * Copyright 1997 by Carnegie Mellon University
13 *
14 * All Rights Reserved
15 *
16 * Permission to use, copy, modify, and distribute this software and its
17 * documentation for any purpose and without fee is hereby granted,
18 * provided that the above copyright notice appear in all copies and that
19 * both that copyright notice and this permission notice appear in
20 * supporting documentation, and that the name of CMU not be
21 * used in advertising or publicity pertaining to distribution of the
22 * software without specific, written prior permission.
23 *
24 * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
25 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
26 * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
27 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
28 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
29 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
30 * SOFTWARE.
31 *
32 ***************************************************************************/
627f6d02 33
db5edad5 34#include "config.h"
35
627f6d02 36#include <stdio.h>
85269fdf 37
38#if HAVE_UNISTD_H
39#include <unistd.h>
db5edad5 40#endif
41#if HAVE_STDLIB_H
627f6d02 42#include <stdlib.h>
db5edad5 43#endif
db5edad5 44#if HAVE_SYS_TYPES_H
627f6d02 45#include <sys/types.h>
db5edad5 46#endif
85269fdf 47#if HAVE_CTYPE_H
48#include <ctype.h>
49#endif
50#if HAVE_GNUMALLOC_H
51#include <gnumalloc.h>
52#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
53#include <malloc.h>
54#endif
55#if HAVE_MEMORY_H
56#include <memory.h>
57#endif
58#ifdef HAVE_STRING_H
59#include <string.h>
60#endif
61#ifdef HAVE_STRINGS_H
62#include <strings.h>
63#endif
64#if HAVE_BSTRING_H
65#include <bstring.h>
66#endif
67#if HAVE_SYS_SOCKET_H
68#include <sys/socket.h>
69#endif
db5edad5 70#if HAVE_NETINET_IN_H
627f6d02 71#include <netinet/in.h>
627f6d02 72#endif
85269fdf 73#if HAVE_ARPA_INET_H
74#include <arpa/inet.h>
75#endif
76#if HAVE_SYS_TIME_H
77#include <sys/time.h>
78#endif
79#if HAVE_NETDB_H
80#include <netdb.h>
627f6d02 81#endif
82
db5edad5 83#include "asn1.h"
85269fdf 84#include "snmp_api_error.h"
db5edad5 85
85269fdf 86
87u_char *asn_build_header(u_char *data, /* IN - ptr to start of object */
88 int *datalength, /* IN/OUT - # of valid bytes */
89 /* left in buffer */
90 u_char type, /* IN - ASN type of object */
91 int length) /* IN - length of object */
92{
93 /* Truth is 0 'cause we don't know yet */
94 return(asn_build_header_with_truth(data, datalength, type, length, 0));
95}
627f6d02 96
97
98/*
85269fdf 99 * asn_parse_int - pulls an int out of an ASN int type.
627f6d02 100 * On entry, datalength is input as the number of valid bytes following
101 * "data". On exit, it is returned as the number of valid bytes
102 * following the end of this object.
103 *
104 * Returns a pointer to the first byte past the end
105 * of this object (i.e. the start of the next object).
106 * Returns NULL on any error.
107 */
85269fdf 108u_char *asn_parse_int(u_char *data, int *datalength,
109 u_char *type, int *intp, int intsize)
110 /* u_char *data; IN - pointer to start of object */
111 /* int *datalength; IN/OUT - # of valid bytes left in buffer */
112 /* u_char *type; OUT - asn type of object */
113 /* int *intp; IN/OUT - pointer to start of output buffer */
114 /* int intsize; IN - size of output buffer */
115{
116 /*
117 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
118 */
119 u_char *bufp = data;
120 u_int asn_length;
121 int value = 0;
122
123 /* Room to store int? */
124 if (intsize != sizeof (int)) {
125 snmp_set_api_error(SNMPERR_ASN_DECODE);
126 return(NULL);
127 }
128
129 /* Type */
130 *type = *bufp++;
131
132 /* Extract length */
133 bufp = asn_parse_length(bufp, &asn_length);
134 if (bufp == NULL)
135 return(NULL);
136
137 /* Make sure the entire int is in the buffer */
138 if (asn_length + (bufp - data) > *datalength) {
139 snmp_set_api_error(SNMPERR_ASN_DECODE);
140 return(NULL);
141 }
142
143 /* Can we store this int? */
144 if (asn_length > intsize) {
145 snmp_set_api_error(SNMPERR_ASN_DECODE);
146 return(NULL);
147 }
148
149 /* Remaining data */
150 *datalength -= (int)asn_length + (bufp - data);
151
152 /* Is the int negative? */
153 if (*bufp & 0x80)
154 value = -1; /* integer is negative */
155
156 /* Extract the bytes */
157 while(asn_length--)
158 value = (value << 8) | *bufp++;
159
160 /* That's it! */
161 *intp = value;
162 return(bufp);
627f6d02 163}
164
627f6d02 165/*
85269fdf 166 * asn_parse_unsigned_int - pulls an unsigned int out of an ASN int type.
627f6d02 167 * On entry, datalength is input as the number of valid bytes following
168 * "data". On exit, it is returned as the number of valid bytes
169 * following the end of this object.
170 *
171 * Returns a pointer to the first byte past the end
172 * of this object (i.e. the start of the next object).
173 * Returns NULL on any error.
174 */
85269fdf 175u_char *asn_parse_unsigned_int(u_char *data, int *datalength,
176 u_char *type, u_int *intp, int intsize)
177 /* u_char *data; IN - pointer to start of object */
178 /* int *datalength; IN/OUT - # of valid bytes left in buffer */
179 /* u_char *type; OUT - asn type of object */
180 /* u_int *intp; IN/OUT - pointer to start of output buffer */
181 /* int intsize; IN - size of output buffer */
182{
183 /*
184 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
185 */
186 u_char *bufp = data;
187 u_int asn_length;
188 int value = 0;
189
190 /* Room to store int? */
191 if (intsize != sizeof (int)) {
192 snmp_set_api_error(SNMPERR_ASN_DECODE);
193 return(NULL);
194 }
195
196 /* Type */
197 *type = *bufp++;
198
199 /* Extract length */
200 bufp = asn_parse_length(bufp, &asn_length);
201 if (bufp == NULL)
202 return(NULL);
203
204 /* Make sure the entire int is in the buffer */
205 if (asn_length + (bufp - data) > *datalength) {
206 snmp_set_api_error(SNMPERR_ASN_DECODE);
207 return(NULL);
208 }
209
210 /* Can we store this int? */
211 if ((asn_length > (intsize + 1)) ||
212 ((asn_length == intsize + 1) && *bufp != 0x00)) {
213 snmp_set_api_error(SNMPERR_ASN_DECODE);
214 return(NULL);
215 }
216
217 /* Remaining data */
218 *datalength -= (int)asn_length + (bufp - data);
219
220 /* Is the int negative? */
221 if (*bufp & 0x80)
222 value = -1; /* integer is negative */
223
224 /* Extract the bytes */
225 while(asn_length--)
226 value = (value << 8) | *bufp++;
227
228 /* That's it! */
229 *intp = value;
230 return(bufp);
627f6d02 231}
232
627f6d02 233/*
234 * asn_build_int - builds an ASN object containing an integer.
235 * On entry, datalength is input as the number of valid bytes following
236 * "data". On exit, it is returned as the number of valid bytes
237 * following the end of this object.
238 *
239 * Returns a pointer to the first byte past the end
240 * of this object (i.e. the start of the next object).
241 * Returns NULL on any error.
242 */
85269fdf 243u_char *asn_build_int(u_char *data, int *datalength,
244 u_char type, int *intp, int intsize)
245 /* u_char *data; IN - pointer to start of output buffer */
246 /* int *datalength; IN/OUT - # of valid bytes left in buffer */
247 /* u_char type; IN - asn type of object */
248 /* int *intp; IN - pointer to start of integer */
249 /* int intsize; IN - size of *intp */
250{
251 /*
252 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
253 */
254 int integer;
255 u_int mask;
256
257 if (intsize != sizeof (int)) {
258 snmp_set_api_error(SNMPERR_ASN_ENCODE);
259 return(NULL);
260 }
261
262 integer = *intp;
263
264 /*
265 * Truncate "unnecessary" bytes off of the most significant end of this
266 * 2's complement integer. There should be no sequence of 9
267 * consecutive 1's or 0's at the most significant end of the
268 * integer.
269 */
270 mask = (u_int)0x1FF << ((8 * (sizeof(int) - 1)) - 1);
271 /* mask is 0xFF800000 on a big-endian machine */
272
273 while((((integer & mask) == 0) || ((integer & mask) == mask))
da2d50d1 274 && intsize > 1) {
85269fdf 275 intsize--;
276 integer <<= 8;
277 }
278
279 data = asn_build_header_with_truth(data, datalength, type, intsize, 1);
280 if (data == NULL)
281 return(NULL);
282
283 /* Enough room for what we just encoded? */
284 if (*datalength < intsize) {
285 snmp_set_api_error(SNMPERR_ASN_ENCODE);
286 return(NULL);
287 }
288
289 /* Insert it */
290 *datalength -= intsize;
291 mask = (u_int)0xFF << (8 * (sizeof(int) - 1));
292 /* mask is 0xFF000000 on a big-endian machine */
293 while(intsize--) {
294 *data++ = (u_char)((integer & mask) >> (8 * (sizeof(int) - 1)));
295 integer <<= 8;
296 }
297 return(data);
627f6d02 298}
299
627f6d02 300/*
301 * asn_build_unsigned_int - builds an ASN object containing an integer.
302 * On entry, datalength is input as the number of valid bytes following
303 * "data". On exit, it is returned as the number of valid bytes
304 * following the end of this object.
305 *
306 * Returns a pointer to the first byte past the end
307 * of this object (i.e. the start of the next object).
308 * Returns NULL on any error.
309 */
85269fdf 310u_char *asn_build_unsigned_int(u_char *data, int *datalength,
311 u_char type, u_int *intp, int intsize)
312 /* u_char *data; IN - pointer to start of output buffer */
313 /* int *datalength; IN/OUT - # of valid bytes left in buffer */
314 /* u_char type; IN - asn type of object */
315 /* u_int *intp; IN - pointer to start of integer */
316 /* int intsize; IN - size of *intp */
317{
318 /*
319 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
320 */
321 u_int integer;
322 u_int mask;
323 int add_null_byte = 0;
324
325 if (intsize != sizeof (int)) {
326 snmp_set_api_error(SNMPERR_ASN_ENCODE);
327 return(NULL);
328 }
329
330 integer = *intp;
331 mask = (u_int)0xFF << (8 * (sizeof(int) - 1));
332 /* mask is 0xFF000000 on a big-endian machine */
333 if ((u_char)((integer & mask) >> (8 * (sizeof(int) - 1))) & 0x80) {
334 /* if MSB is set */
335 add_null_byte = 1;
336 intsize++;
337 }
338
339 /*
340 * Truncate "unnecessary" bytes off of the most significant end of
341 * this 2's complement integer.
342 * There should be no sequence of 9 consecutive 1's or 0's at the
343 * most significant end of the integer.
344 */
345 mask = (u_int)0x1FF << ((8 * (sizeof(int) - 1)) - 1);
346 /* mask is 0xFF800000 on a big-endian machine */
347 while((((integer & mask) == 0)
348 || ((integer & mask) == mask)) && intsize > 1) {
349 intsize--;
350 integer <<= 8;
351 }
352
353 data = asn_build_header_with_truth(data, datalength, type, intsize, 1);
354 if (data == NULL)
355 return(NULL);
356
357 if (*datalength < intsize) {
358 snmp_set_api_error(SNMPERR_ASN_ENCODE);
359 return(NULL);
360 }
361
362 *datalength -= intsize;
363 if (add_null_byte == 1) {
364 *data++ = '\0';
365 intsize--;
366 }
367
368 mask = (u_int)0xFF << (8 * (sizeof(int) - 1));
369 /* mask is 0xFF000000 on a big-endian machine */
370 while(intsize--) {
371 *data++ = (u_char)((integer & mask) >> (8 * (sizeof(int) - 1)));
372 integer <<= 8;
373 }
374 return(data);
627f6d02 375}
376
627f6d02 377/*
378 * asn_parse_string - pulls an octet string out of an ASN octet string type.
379 * On entry, datalength is input as the number of valid bytes following
380 * "data". On exit, it is returned as the number of valid bytes
381 * following the beginning of the next object.
382 *
383 * "string" is filled with the octet string.
384 *
385 * Returns a pointer to the first byte past the end
386 * of this object (i.e. the start of the next object).
387 * Returns NULL on any error.
388 */
85269fdf 389u_char *asn_parse_string(u_char *data, int *datalength,
390 u_char *type, u_char *string, int *strlength)
391 /* u_char *data; IN - pointer to start of object */
392 /* int *datalength; IN/OUT - # of valid bytes left in buffer */
393 /* u_char *type; OUT - asn type of object */
394 /* u_char *string; IN/OUT - pointer to start of output buffer */
395 /* int *strlength; IN/OUT - size of output buffer */
396{
397 /*
398 * ASN.1 octet string ::= primstring | cmpdstring
399 * primstring ::= 0x04 asnlength byte {byte}*
400 * cmpdstring ::= 0x24 asnlength string {string}*
401 */
402 u_char *bufp = data;
403 u_int asn_length;
404
405 *type = *bufp++;
406 bufp = asn_parse_length(bufp, &asn_length);
407 if (bufp == NULL)
408 return(NULL);
409
410 if (asn_length + (bufp - data) > *datalength) {
411 snmp_set_api_error(SNMPERR_ASN_DECODE);
412 return(NULL);
413 }
414
415 if (asn_length > *strlength) {
416 snmp_set_api_error(SNMPERR_ASN_DECODE);
417 return(NULL);
418 }
419
420 xmemcpy((char *)string, (char *)bufp, (int)asn_length);
421 *strlength = (int)asn_length;
422 *datalength -= (int)asn_length + (bufp - data);
423 return(bufp + asn_length);
627f6d02 424}
425
627f6d02 426/*
85269fdf 427 * asn_build_string - Builds an ASN octet string object containing the input
428 * string. On entry, datalength is input as the number of valid bytes
429 * following "data". On exit, it is returned as the number of valid bytes
627f6d02 430 * following the beginning of the next object.
431 *
432 * Returns a pointer to the first byte past the end
433 * of this object (i.e. the start of the next object).
434 * Returns NULL on any error.
435 */
85269fdf 436u_char *asn_build_string(u_char *data, int *datalength,
437 u_char type, u_char *string, int strlength)
438 /* u_char *data; IN - pointer to start of object */
439 /* int *datalength; IN/OUT - # of valid bytes left in buf */
440 /* u_char type; IN - ASN type of string */
441 /* u_char *string; IN - pointer to start of input buffer */
442 /* int strlength; IN - size of input buffer */
443{
444 /*
445 * ASN.1 octet string ::= primstring | cmpdstring
446 * primstring ::= 0x04 asnlength byte {byte}*
447 * cmpdstring ::= 0x24 asnlength string {string}*
448 * This code will never send a compound string.
449 */
450 data = asn_build_header_with_truth(data, datalength, type, strlength, 1);
451 if (data == NULL)
452 return(NULL);
453
454 if (*datalength < strlength) {
455 snmp_set_api_error(SNMPERR_ASN_DECODE);
456 return(NULL);
457 }
458
459 xmemcpy((char *)data, (char *)string, strlength);
460 *datalength -= strlength;
461 return(data + strlength);
627f6d02 462}
463
464
465/*
466 * asn_parse_header - interprets the ID and length of the current object.
467 * On entry, datalength is input as the number of valid bytes following
468 * "data". On exit, it is returned as the number of valid bytes
469 * in this object following the id and length.
470 *
471 * Returns a pointer to the first byte of the contents of this object.
472 * Returns NULL on any error.
473 */
85269fdf 474u_char *asn_parse_header(u_char *data, int *datalength, u_char *type)
475 /* u_char *data; IN - pointer to start of object */
476 /* int *datalength; IN/OUT - # of valid bytes left in buffer */
477 /* u_char *type; OUT - ASN type of object */
478{
479 u_char *bufp = data;
480 int header_len;
481 u_int asn_length;
482
483 /* this only works on data types < 30, i.e. no extension octets */
484 if (IS_EXTENSION_ID(*bufp)) {
485 snmp_set_api_error(SNMPERR_ASN_DECODE);
486 return(NULL);
487 }
488
489 *type = *bufp;
490 bufp = asn_parse_length(bufp + 1, &asn_length);
491 if (bufp == NULL)
492 return(NULL);
493
494 header_len = bufp - data;
495 if (header_len + asn_length > *datalength) {
496 snmp_set_api_error(SNMPERR_ASN_DECODE);
497 return(NULL);
498 }
499
500 *datalength = (int)asn_length;
501 return(bufp);
627f6d02 502}
503
504/*
505 * asn_build_header - builds an ASN header for an object with the ID and
506 * length specified.
507 * On entry, datalength is input as the number of valid bytes following
508 * "data". On exit, it is returned as the number of valid bytes
509 * in this object following the id and length.
510 *
511 * This only works on data types < 30, i.e. no extension octets.
512 * The maximum length is 0xFFFF;
513 *
514 * Returns a pointer to the first byte of the contents of this object.
515 * Returns NULL on any error.
516 */
da2d50d1 517
85269fdf 518u_char *asn_build_header_with_truth(u_char *data, int *datalength,
519 u_char type, int length, int truth)
520 /* u_char *data; IN - pointer to start of object */
521 /* int *datalength; IN/OUT - # of valid bytes left in buffer */
522 /* u_char type; IN - ASN type of object */
523 /* int length; IN - length of object */
524 /* int truth; IN - Whether length is truth */
525{
526 if (*datalength < 1) {
527 snmp_set_api_error(SNMPERR_ASN_ENCODE);
528 return(NULL);
529 }
530
531 *data++ = type;
532 (*datalength)--;
533 return(asn_build_length(data, datalength, length, truth));
627f6d02 534}
535
536/*
537 * asn_build_sequence - builds an ASN header for a sequence with the ID and
538 * length specified.
539 * On entry, datalength is input as the number of valid bytes following
540 * "data". On exit, it is returned as the number of valid bytes
541 * in this object following the id and length.
542 *
543 * This only works on data types < 30, i.e. no extension octets.
544 * The maximum length is 0xFFFF;
545 *
546 * Returns a pointer to the first byte of the contents of this object.
547 * Returns NULL on any error.
548 */
85269fdf 549u_char *asn_build_sequence(u_char *data, int *datalength,
550 u_char type, int length)
551 /* u_char *data; IN - pointer to start of object */
552 /* int *datalength; IN/OUT - # of valid bytes left in buffer */
553 /* u_char type; IN - ASN type of object */
554 /* int length; IN - length of object */
555{
556 *datalength -= 4;
557 if (*datalength < 0) {
558 *datalength += 4; /* fix up before punting */
559 snmp_set_api_error(SNMPERR_ASN_ENCODE);
560 return(NULL);
561 }
562
563 *data++ = type;
564 *data++ = (u_char)(0x02 | ASN_LONG_LEN);
565 *data++ = (u_char)((length >> 8) & 0xFF);
566 *data++ = (u_char)(length & 0xFF);
567 return(data);
627f6d02 568}
569
570/*
571 * asn_parse_length - interprets the length of the current object.
572 * On exit, length contains the value of this length field.
573 *
574 * Returns a pointer to the first byte after this length
575 * field (aka: the start of the data field).
576 * Returns NULL on any error.
577 */
85269fdf 578u_char *asn_parse_length(u_char *data, u_int *length)
579 /* u_char *data; IN - pointer to start of length field */
580 /* u_int *length; OUT - value of length field */
581{
582 u_char lengthbyte = *data;
583
584 if (lengthbyte & ASN_LONG_LEN) {
585 lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */
586
587 if (lengthbyte == 0) {
588 snmp_set_api_error(SNMPERR_ASN_DECODE);
589 return(NULL);
627f6d02 590 }
85269fdf 591
592 if (lengthbyte > sizeof(int)) {
593 snmp_set_api_error(SNMPERR_ASN_DECODE);
594 return(NULL);
595 }
596
597 *length = (u_int)0;
598 xmemcpy((char *)(length), (char *)data + 1, (int)lengthbyte);
599 *length = ntohl(*length);
600 *length >>= (8 * ((sizeof *length) - lengthbyte));
601 return(data + lengthbyte + 1);
602
603 }
604
605 /* short asnlength */
606
607 *length = (int)lengthbyte;
608 return(data + 1);
627f6d02 609}
610
85269fdf 611
612u_char *asn_build_length(u_char *data, int *datalength,
613 int length, int truth)
614 /* u_char *data; IN - pointer to start of object */
615 /* int *datalength; IN/OUT - # of valid bytes left in buf */
616 /* int length; IN - length of object */
617 /* int truth; IN - If 1, this is the true len. */
618{
619 u_char *start_data = data;
620
621 if (truth) {
627f6d02 622
623 /* no indefinite lengths sent */
da2d50d1 624 if (length < 0x80) {
85269fdf 625 if (*datalength < 1) {
626 snmp_set_api_error(SNMPERR_ASN_ENCODE);
627 return(NULL);
628 }
629 *data++ = (u_char)length;
630
da2d50d1 631 } else if (length <= 0xFF) {
85269fdf 632 if (*datalength < 2) {
633 snmp_set_api_error(SNMPERR_ASN_ENCODE);
634 return(NULL);
635 }
636 *data++ = (u_char)(0x01 | ASN_LONG_LEN);
637 *data++ = (u_char)length;
638 } else { /* 0xFF < length <= 0xFFFF */
639 if (*datalength < 3) {
640 snmp_set_api_error(SNMPERR_ASN_ENCODE);
641 return(NULL);
642 }
643 *data++ = (u_char)(0x02 | ASN_LONG_LEN);
644 *data++ = (u_char)((length >> 8) & 0xFF);
645 *data++ = (u_char)(length & 0xFF);
646 }
647
648 } else {
649
650 /* Don't know if this is the true length. Make sure it's large
651 * enough for later.
652 */
653 if (*datalength < 3) {
654 snmp_set_api_error(SNMPERR_ASN_ENCODE);
655 return(NULL);
627f6d02 656 }
85269fdf 657 *data++ = (u_char)(0x02 | ASN_LONG_LEN);
658 *data++ = (u_char)((length >> 8) & 0xFF);
659 *data++ = (u_char)(length & 0xFF);
660 }
627f6d02 661
85269fdf 662 *datalength -= (data - start_data);
663 return(data);
627f6d02 664}
665
666/*
85269fdf 667 * asn_parse_objid - pulls an object indentifier out of an ASN object
668 * identifier type.
627f6d02 669 * On entry, datalength is input as the number of valid bytes following
670 * "data". On exit, it is returned as the number of valid bytes
671 * following the beginning of the next object.
672 *
673 * "objid" is filled with the object identifier.
674 *
675 * Returns a pointer to the first byte past the end
676 * of this object (i.e. the start of the next object).
677 * Returns NULL on any error.
678 */
85269fdf 679u_char *asn_parse_objid(u_char *data, int *datalength,
680 u_char *type, oid *objid, int *objidlength)
681 /* u_char *data; IN - pointer to start of object */
682 /* int *datalength; IN/OUT - # of valid bytes left in buf */
683 /* u_char *type; OUT - ASN type of object */
684 /* oid *objid; IN/OUT - pointer to start of output buffer */
685 /* int *objidlength; IN/OUT - number of sub-id's in objid */
686{
687 /*
688 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
689 * subidentifier ::= {leadingbyte}* lastbyte
690 * leadingbyte ::= 1 7bitvalue
691 * lastbyte ::= 0 7bitvalue
692 */
693 u_char *bufp = data;
694 oid *oidp = objid + 1;
695 u_int subidentifier;
696 int length;
697 u_int asn_length;
698
699 *type = *bufp++;
700 bufp = asn_parse_length(bufp, &asn_length);
701 if (bufp == NULL)
702 return(NULL);
703
704 if (asn_length + (bufp - data) > *datalength) {
705 snmp_set_api_error(SNMPERR_ASN_DECODE);
706 return(NULL);
707 }
708 *datalength -= (int)asn_length + (bufp - data);
709
710 /* Handle invalid object identifier encodings of the form 06 00 robustly */
711 if (asn_length == 0)
712 objid[0] = objid[1] = 0;
713
714 length = asn_length;
715 (*objidlength)--; /* account for expansion of first byte */
716 while (length > 0 && (*objidlength)-- > 0) {
717 subidentifier = 0;
718
719 do { /* shift and add in low order 7 bits */
720 subidentifier = (subidentifier << 7)
721 + (*(u_char *)bufp & ~ASN_BIT8);
722 length--;
723 } while (*(u_char *)bufp++ & ASN_BIT8);
724
725 /* while last byte has high bit clear */
726 if (subidentifier > (u_int)MAX_SUBID) {
727 snmp_set_api_error(SNMPERR_ASN_DECODE);
728 return(NULL);
729 }
730 *oidp++ = (oid)subidentifier;
731 }
732
733 /*
734 * The first two subidentifiers are encoded into the first component
735 * with the value (X * 40) + Y, where:
736 * X is the value of the first subidentifier.
737 * Y is the value of the second subidentifier.
738 */
739 subidentifier = (u_int)objid[1];
740 if (subidentifier == 0x2B) {
741 objid[0] = 1;
742 objid[1] = 3;
743 } else {
744 objid[1] = (u_char)(subidentifier % 40);
745 objid[0] = (u_char)((subidentifier - objid[1]) / 40);
746 }
747
748 *objidlength = (int)(oidp - objid);
749 return(bufp);
627f6d02 750}
751
752/*
753 * asn_build_objid - Builds an ASN object identifier object containing the
754 * input string.
755 * On entry, datalength is input as the number of valid bytes following
756 * "data". On exit, it is returned as the number of valid bytes
757 * following the beginning of the next object.
758 *
759 * Returns a pointer to the first byte past the end
760 * of this object (i.e. the start of the next object).
761 * Returns NULL on any error.
762 */
85269fdf 763u_char *asn_build_objid(u_char *data, int *datalength,
764 u_char type, oid *objid, int objidlength)
765 /* u_char *data; IN - pointer to start of object */
766 /* int *datalength; IN/OUT - # of valid bytes left in buf */
767 /* u_char type; IN - ASN type of object */
768 /* oid *objid; IN - pointer to start of input buffer */
769 /* int objidlength; IN - number of sub-id's in objid */
770{
771 /*
772 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
773 * subidentifier ::= {leadingbyte}* lastbyte
774 * leadingbyte ::= 1 7bitvalue
775 * lastbyte ::= 0 7bitvalue
776 */
777 u_char buf[MAX_OID_LEN];
778 u_char *bp = buf;
779 oid *op = objid;
780 int asnlength;
781 u_int subid, mask, testmask;
782 int bits, testbits;
783
784 if (objidlength < 2) {
785 *bp++ = 0;
786 objidlength = 0;
787 } else {
788 *bp++ = op[1] + (op[0] * 40);
789 objidlength -= 2;
790 op += 2;
791 }
792
793 while(objidlength-- > 0) {
794 subid = *op++;
795 if (subid < 127) { /* off by one? */
796 *bp++ = subid;
627f6d02 797 } else {
85269fdf 798 mask = 0x7F; /* handle subid == 0 case */
799 bits = 0;
800 /* testmask *MUST* !!!! be of an unsigned type */
801 for(testmask = 0x7F, testbits = 0; testmask != 0;
802 testmask <<= 7, testbits += 7) {
803 if (subid & testmask) { /* if any bits set */
804 mask = testmask;
805 bits = testbits;
627f6d02 806 }
85269fdf 807 }
808 /* mask can't be zero here */
809 for(;mask != 0x7F; mask >>= 7, bits -= 7) {
810 /* fix a mask that got truncated above */
811 if (mask == 0x1E00000)
812 mask = 0xFE00000;
813 *bp++ = (u_char)(((subid & mask) >> bits) | ASN_BIT8);
814 }
815 *bp++ = (u_char)(subid & mask);
816 }
817 }
818
819 asnlength = bp - buf;
820 data = asn_build_header_with_truth(data, datalength, type, asnlength, 1);
821 if (data == NULL)
822 return(NULL);
823 if (*datalength < asnlength) {
824 snmp_set_api_error(SNMPERR_ASN_DECODE);
825 return(NULL);
826 }
827 xmemcpy((char *)data, (char *)buf, asnlength);
828 *datalength -= asnlength;
829 return(data + asnlength);
627f6d02 830}
831
832/*
833 * asn_parse_null - Interprets an ASN null type.
834 * On entry, datalength is input as the number of valid bytes following
835 * "data". On exit, it is returned as the number of valid bytes
836 * following the beginning of the next object.
837 *
838 * Returns a pointer to the first byte past the end
839 * of this object (i.e. the start of the next object).
840 * Returns NULL on any error.
841 */
85269fdf 842u_char *asn_parse_null(u_char *data, int *datalength, u_char *type)
843 /* u_char *data; IN - pointer to start of object */
844 /* int *datalength; IN/OUT - # of valid bytes left in buf */
845 /* u_char *type; OUT - ASN type of object */
846{
847 /*
848 * ASN.1 null ::= 0x05 0x00
849 */
850 u_char *bufp = data;
851 u_int asn_length;
852
853 *type = *bufp++;
854 bufp = asn_parse_length(bufp, &asn_length);
855 if (bufp == NULL)
856 return(NULL);
857
858 if (asn_length != 0) {
859 snmp_set_api_error(SNMPERR_ASN_DECODE);
860 return(NULL);
861 }
862
863 *datalength -= (bufp - data);
864 return(bufp + asn_length);
627f6d02 865}
866
627f6d02 867/*
868 * asn_build_null - Builds an ASN null object.
869 * On entry, datalength is input as the number of valid bytes following
870 * "data". On exit, it is returned as the number of valid bytes
871 * following the beginning of the next object.
872 *
873 * Returns a pointer to the first byte past the end
874 * of this object (i.e. the start of the next object).
875 * Returns NULL on any error.
876 */
85269fdf 877u_char *asn_build_null(u_char *data, int *datalength, u_char type)
878 /* u_char *data; IN - pointer to start of object */
879 /* int *datalength; IN/OUT - # of valid bytes left in buf */
880 /* u_char type; IN - ASN type of object */
881{
882 /*
883 * ASN.1 null ::= 0x05 0x00
884 */
885 return(asn_build_header_with_truth(data, datalength, type, 0, 1));
627f6d02 886}
887
888/*
889 * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
890 * On entry, datalength is input as the number of valid bytes following
891 * "data". On exit, it is returned as the number of valid bytes
892 * following the beginning of the next object.
893 *
894 * "string" is filled with the bit string.
895 *
896 * Returns a pointer to the first byte past the end
897 * of this object (i.e. the start of the next object).
898 * Returns NULL on any error.
899 */
85269fdf 900u_char *asn_parse_bitstring(u_char *data, int *datalength,
901 u_char *type, u_char *string, int *strlength)
902 /* u_char *data; IN - pointer to start of object */
903 /* int *datalength; IN/OUT - # of valid bytes left in buf */
904 /* u_char *type; OUT - asn type of object */
905 /* u_char *string; IN/OUT - pointer to start of output buf */
906 /* int *strlength; IN/OUT - size of output buffer */
907{
908 /*
909 * bitstring ::= 0x03 asnlength unused {byte}*
910 */
911 u_char *bufp = data;
912 u_int asn_length;
913
914 *type = *bufp++;
915 bufp = asn_parse_length(bufp, &asn_length);
916 if (bufp == NULL)
917 return(NULL);
918
919 if (asn_length + (bufp - data) > *datalength) {
920 snmp_set_api_error(SNMPERR_ASN_DECODE);
921 return(NULL);
922 }
923
924 if (asn_length > *strlength) {
925 snmp_set_api_error(SNMPERR_ASN_DECODE);
926 return(NULL);
927 }
928
929 if (asn_length < 1) {
930 snmp_set_api_error(SNMPERR_ASN_DECODE);
931 return(NULL);
932 }
933
934 if ((int)(*(char *)bufp) < 0 || (int)(*bufp) > 7) {
935 snmp_set_api_error(SNMPERR_ASN_DECODE);
936 return(NULL);
937 }
938
939 xmemcpy((char *)string, (char *)bufp, (int)asn_length);
940 *strlength = (int)asn_length;
941 *datalength -= (int)asn_length + (bufp - data);
942 return(bufp + asn_length);
627f6d02 943}
944
627f6d02 945/*
946 * asn_build_bitstring - Builds an ASN bit string object containing the
947 * input string.
948 * On entry, datalength is input as the number of valid bytes following
949 * "data". On exit, it is returned as the number of valid bytes
950 * following the beginning of the next object.
951 *
952 * Returns a pointer to the first byte past the end
953 * of this object (i.e. the start of the next object).
954 * Returns NULL on any error.
955 */
85269fdf 956u_char *asn_build_bitstring(u_char *data, int *datalength,
957 u_char type, u_char *string, int strlength)
958 /* u_char *data; IN - pointer to start of object */
959 /* int *datalength; IN/OUT - # of valid bytes left in buf */
960 /* u_char type; IN - ASN type of string */
961 /* u_char *string; IN - pointer to start of input buffer */
962 /* int strlength; IN - size of input buffer */
963{
964 /*
965 * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
966 */
967 if ((strlength < 1) || ((*(char *)string) < 0) || ((*string) > 7)) {
968 snmp_set_api_error(SNMPERR_ASN_ENCODE);
969 return(NULL);
970 }
971
972 data = asn_build_header_with_truth(data, datalength, type, strlength, 1);
973 if (data == NULL)
974 return(NULL);
975
976 if (*datalength < strlength) {
977 snmp_set_api_error(SNMPERR_ASN_ENCODE);
978 return(NULL);
979 }
980
981 xmemcpy((char *)data, (char *)string, strlength);
982 *datalength -= strlength;
983 return(data + strlength);
627f6d02 984}
985
986
987/*
85269fdf 988 * To do: Write an asn_parse_exception function to go with the new
989 * asn_build_exception function below so that the exceptional values can
990 * be handled in input packets aswell as output ones.
627f6d02 991 */
627f6d02 992
993/*
85269fdf 994 * asn_build_exception - Builds an ASN exception object.
627f6d02 995 * On entry, datalength is input as the number of valid bytes following
996 * "data". On exit, it is returned as the number of valid bytes
85269fdf 997 * following the beginning of the next object.
627f6d02 998 *
999 * Returns a pointer to the first byte past the end
1000 * of this object (i.e. the start of the next object).
1001 * Returns NULL on any error.
85269fdf 1002 *
1003 * ASN.1 variable exception ::= 0x8i 0x00, where 'i' is one of these
1004 * exception identifiers:
1005 * 0 -- noSuchObject
1006 * 1 -- noSuchInstance
1007 * 2 -- endOfMibView
1008 */
1009u_char *asn_build_exception(u_char *data, int *datalength, u_char type)
1010 /* u_char *data; IN - pointer to start of object */
1011 /* int *datalength; IN/OUT - # of valid bytes left in buf */
1012 /* u_char type; IN - ASN type of object */
1013{
1014 return(asn_build_header_with_truth(data, datalength, type, 0, 1));
627f6d02 1015}