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