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