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