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 * Portions of this file are subject to the following copyright(s). See
10 * the Net-SNMP's COPYING file for more details and other copyrights
11 * that may apply:
12 *
13 * Portions of this file are copyrighted by:
14 * Copyright (c) 2016 VMware, Inc. All rights reserved.
15 * Use is subject to license terms specified in the COPYING file
16 * distributed with the Net-SNMP package.
17 */
18 /**********************************************************************
19 Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
20
21 All Rights Reserved
22
23 Permission to use, copy, modify, and distribute this software and its
24 documentation for any purpose and without fee is hereby granted,
25 provided that the above copyright notice appear in all copies and that
26 both that copyright notice and this permission notice appear in
27 supporting documentation, and that the name of CMU not be
28 used in advertising or publicity pertaining to distribution of the
29 software without specific, written prior permission.
30
31 CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
32 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
33 CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
34 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
35 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
36 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
37 SOFTWARE.
38 ******************************************************************/
39 /**
40 * @defgroup asn1_packet_parse asn1 parsing and datatype manipulation routines.
41 * @ingroup library
42 *
43 * @{
44 *
45 * Note on
46 *
47 * Re-allocating reverse ASN.1 encoder functions. Synopsis:
48 *
49 * \code
50 *
51 * u_char *buf = (u_char*)malloc(100);
52 * u_char type = (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
53 * size_t buf_len = 100, offset = 0;
54 * long data = 12345;
55 * int allow_realloc = 1;
56 *
57 * if (asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
58 * type, &data, sizeof(long)) == 0) {
59 * error;
60 * }
61 *
62 * \endcode
63 *
64 * NOTE WELL: after calling one of these functions with allow_realloc
65 * non-zero, buf might have moved, buf_len might have grown and
66 * offset will have increased by the size of the encoded data.
67 * You should **NEVER** do something like this:
68 *
69 * \code
70 *
71 * u_char *buf = (u_char *)malloc(100), *ptr;
72 * u_char type = (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
73 * size_t buf_len = 100, offset = 0;
74 * long data1 = 1234, data2 = 5678;
75 * int rc = 0, allow_realloc = 1;
76 *
77 * rc = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
78 * type, &data1, sizeof(long));
79 * ptr = buf[buf_len - offset]; / * points at encoding of data1 * /
80 * if (rc == 0) {
81 * error;
82 * }
83 * rc = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
84 * type, &data2, sizeof(long));
85 * make use of ptr here;
86 *
87 * \endcode
88 *
89 * ptr is **INVALID** at this point. In general, you should store the
90 * offset value and compute pointers when you need them:
91 *
92 *
93 * \code
94 *
95 * u_char *buf = (u_char *)malloc(100), *ptr;
96 * u_char type = (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
97 * size_t buf_len = 100, offset = 0, ptr_offset;
98 * long data1 = 1234, data2 = 5678;
99 * int rc = 0, allow_realloc = 1;
100 *
101 * rc = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
102 * type, &data1, sizeof(long));
103 * ptr_offset = offset;
104 * if (rc == 0) {
105 * error;
106 * }
107 * rc = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
108 * type, &data2, sizeof(long));
109 * ptr = buf + buf_len - ptr_offset
110 * make use of ptr here;
111 *
112 * \endcode
113 *
114 *
115 * Here, you can see that ptr will be a valid pointer even if the block of
116 * memory has been moved, as it may well have been. Plenty of examples of
117 * usage all over asn1.c, snmp_api.c, snmpusm.c.
118 *
119 * The other thing you should **NEVER** do is to pass a pointer to a buffer
120 * on the stack as the first argument when allow_realloc is non-zero, unless
121 * you really know what you are doing and your machine/compiler allows you to
122 * free non-heap memory. There are rumours that such things exist, but many
123 * consider them no more than the wild tales of a fool.
124 *
125 * Of course, you can pass allow_realloc as zero, to indicate that you do not
126 * wish the packet buffer to be reallocated for some reason; perhaps because
127 * it is on the stack. This may be useful to emulate the functionality of
128 * the old API:
129 *
130 * \code
131 *
132 * u_char my_static_buffer[100], *cp = NULL;
133 * size_t my_static_buffer_len = 100;
134 * float my_pi = (float)22/(float)7;
135 *
136 * cp = asn_rbuild_float(my_static_buffer, &my_static_buffer_len,
137 * ASN_OPAQUE_FLOAT, &my_pi, sizeof(float));
138 * if (cp == NULL) {
139 * error;
140 * }
141 *
142 * \endcode
143 *
144 * IS EQUIVALENT TO:
145 *
146 * \code
147 *
148 * u_char my_static_buffer[100];
149 * size_t my_static_buffer_len = 100, my_offset = 0;
150 * float my_pi = (float)22/(float)7;
151 * int rc = 0;
152 *
153 * rc = asn_realloc_rbuild_float(&my_static_buffer, &my_static_buffer_len,
154 * &my_offset, 0,
155 * ASN_OPAQUE_FLOAT, &my_pi, sizeof(float));
156 * if (rc == 0) {
157 * error;
158 * }
159 * \endcode
160 *
161 */
162
163
164 #include <net-snmp/net-snmp-config.h>
165
166 #ifdef KINETICS
167 #include "gw.h"
168 #endif
169
170 #if HAVE_STRING_H
171 #include <string.h>
172 #else
173 #include <strings.h>
174 #endif
175
176 #include <sys/types.h>
177 #include <stdio.h>
178 #ifdef HAVE_STDINT_H
179 #include <stdint.h>
180 #endif
181 #ifdef HAVE_STDLIB_H
182 #include <stdlib.h>
183 #endif
184 #if HAVE_NETINET_IN_H
185 #include <netinet/in.h>
186 #endif
187
188 #ifdef vms
189 #include <in.h>
190 #endif
191
192 #include <net-snmp/output_api.h>
193 #include <net-snmp/utilities.h>
194
195 #include <net-snmp/library/asn1.h>
196 #include <net-snmp/library/int64.h>
197 #include <net-snmp/library/mib.h>
198
199 #ifndef NULL
200 #define NULL 0
201 #endif
202
203 #include <net-snmp/library/snmp_api.h>
204
205 #ifndef INT32_MAX
206 # define INT32_MAX 2147483647
207 #endif
208
209 #ifndef INT32_MIN
210 # define INT32_MIN (0 - INT32_MAX - 1)
211 #endif
212
213
214 #if SIZEOF_LONG == 4
215 # define CHECK_OVERFLOW_S(x,y)
216 # define CHECK_OVERFLOW_U(x,y)
217 #else
218 # define CHECK_OVERFLOW_S(x,y) do { \
219 if (x > INT32_MAX) { \
220 DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
221 x &= 0xffffffff; \
222 } else if (x < INT32_MIN) { \
223 DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
224 x = 0 - (x & 0xffffffff); \
225 } \
226 } while(0)
227
228 # define CHECK_OVERFLOW_U(x,y) do { \
229 if (x > UINT32_MAX) { \
230 x &= 0xffffffff; \
231 DEBUGMSG(("asn","truncating unsigned value to 32 bits (%d)\n",y)); \
232 } \
233 } while(0)
234 #endif
235
236 /**
237 * @internal
238 * output an error for a wrong size
239 *
240 * @param str error string
241 * @param wrongsize wrong size
242 * @param rightsize expected size
243 */
244 static
245 void
_asn_size_err(const char * str,size_t wrongsize,size_t rightsize)246 _asn_size_err(const char *str, size_t wrongsize, size_t rightsize)
247 {
248 char ebuf[128];
249
250 snprintf(ebuf, sizeof(ebuf),
251 "%s size %lu: s/b %lu", str,
252 (unsigned long)wrongsize, (unsigned long)rightsize);
253 ebuf[ sizeof(ebuf)-1 ] = 0;
254 ERROR_MSG(ebuf);
255 }
256
257 /**
258 * @internal
259 * output an error for a wrong type
260 *
261 * @param str error string
262 * @param wrongtype wrong type
263 */
264 static
265 void
_asn_type_err(const char * str,int wrongtype)266 _asn_type_err(const char *str, int wrongtype)
267 {
268 char ebuf[128];
269
270 snprintf(ebuf, sizeof(ebuf), "%s type %d", str, wrongtype);
271 ebuf[ sizeof(ebuf)-1 ] = 0;
272 ERROR_MSG(ebuf);
273 }
274
275 /**
276 * @internal
277 * output an error for a wrong length
278 *
279 * @param str error string
280 * @param wrongsize wrong length
281 * @param rightsize expected length
282 */
283 static
284 void
_asn_length_err(const char * str,size_t wrongsize,size_t rightsize)285 _asn_length_err(const char *str, size_t wrongsize, size_t rightsize)
286 {
287 char ebuf[128];
288
289 snprintf(ebuf, sizeof(ebuf),
290 "%s length %lu too large: exceeds %lu", str,
291 (unsigned long)wrongsize, (unsigned long)rightsize);
292 ebuf[ sizeof(ebuf)-1 ] = 0;
293 ERROR_MSG(ebuf);
294 }
295
296 /**
297 * @internal
298 * output an error for a wrong length
299 *
300 * @param str error string
301 * @param wrongsize wrong length
302 * @param rightsize expected length
303 */
304 static
305 void
_asn_short_err(const char * str,size_t wrongsize,size_t rightsize)306 _asn_short_err(const char *str, size_t wrongsize, size_t rightsize)
307 {
308 char ebuf[128];
309
310 snprintf(ebuf, sizeof(ebuf),
311 "%s length %lu too short: need %lu", str,
312 (unsigned long)wrongsize, (unsigned long)rightsize);
313 ebuf[ sizeof(ebuf)-1 ] = 0;
314 ERROR_MSG(ebuf);
315 }
316
317 /**
318 * @internal
319 * checks a buffer with a length + data to see if it is big enough for
320 * the length encoding and the data of the parsed length.
321 *
322 * @param IN pkt The buffer
323 * @param IN pkt_len The length of the bugger
324 * @param OUT data_len Pointer to size of data
325 *
326 * @return Pointer to start of data or NULL if pkt isn't long enough
327 *
328 * pkt = get_buf(..., &pkt_len);
329 * data = asn_parse_nlength(pkt, pkt_len, &data_len);
330 * if (NULL == data) { handle_error(); }
331 *
332 */
333 u_char *
asn_parse_nlength(u_char * pkt,size_t pkt_len,u_long * data_len)334 asn_parse_nlength(u_char *pkt, size_t pkt_len, u_long *data_len)
335 {
336 int len_len;
337
338 if (pkt_len < 1)
339 return NULL; /* always too short */
340
341 if (NULL == pkt || NULL == data_len || NULL == data_len)
342 return NULL;
343
344 *data_len = 0;
345
346 if (*pkt & 0x80) {
347 /*
348 * long length; first byte is length of length (after masking high bit)
349 */
350 len_len = (int) ((*pkt & ~0x80) + 1);
351 if (pkt_len < len_len)
352 return NULL; /* still too short for length and data */
353
354 /* now we know we have enough data to parse length */
355 if (NULL == asn_parse_length(pkt, data_len))
356 return NULL; /* propagate error from asn_parse_length */
357 } else {
358 /*
359 * short length; first byte is the length
360 */
361 len_len = 1;
362 *data_len = *pkt;
363 }
364
365 if ((*data_len + len_len) > pkt_len)
366 return NULL;
367
368 return (pkt + len_len);
369 }
370
371 #if 0
372 /**
373 * @internal
374 * call after asn_parse_length to verify result.
375 *
376 * @param str error string
377 * @param bufp start of buffer
378 * @param data start of data
379 * @param plen ? parsed length
380 * @param dlen ? data/buf length
381 *
382 * @return 1 on error 0 on success
383 */
384 static
385 int
386 _asn_parse_length_check(const char *str,
387 const u_char * bufp, const u_char * data,
388 u_long plen, size_t dlen)
389 {
390 char ebuf[128];
391 size_t header_len;
392
393 if (bufp == NULL) {
394 /*
395 * error message is set
396 */
397 return 1;
398 }
399 header_len = bufp - data;
400 if (plen > SNMP_MAX_PACKET_LEN || header_len > SNMP_MAX_PACKET_LEN ||
401 ((size_t) plen + header_len) > dlen) {
402 snprintf(ebuf, sizeof(ebuf),
403 "%s: message overflow: %d len + %d delta > %d len",
404 str, (int) plen, (int) header_len, (int) dlen);
405 ebuf[ sizeof(ebuf)-1 ] = 0;
406 ERROR_MSG(ebuf);
407 return 1;
408 }
409 return 0;
410 }
411 #endif
412
413
414 /**
415 * @internal
416 * call after asn_build_header to verify result.
417 *
418 * @param str error string to output
419 * @param data data pointer to verify (NULL => error )
420 * @param datalen data len to check
421 * @param typedlen type length
422 *
423 * @return 0 on success, 1 on error
424 */
425 static
426 int
_asn_build_header_check(const char * str,const u_char * data,size_t datalen,size_t typedlen)427 _asn_build_header_check(const char *str, const u_char * data,
428 size_t datalen, size_t typedlen)
429 {
430 char ebuf[128];
431
432 if (data == NULL) {
433 /*
434 * error message is set
435 */
436 return 1;
437 }
438 if (datalen < typedlen) {
439 snprintf(ebuf, sizeof(ebuf),
440 "%s: bad header, length too short: %lu < %lu", str,
441 (unsigned long)datalen, (unsigned long)typedlen);
442 ebuf[ sizeof(ebuf)-1 ] = 0;
443 ERROR_MSG(ebuf);
444 return 1;
445 }
446 return 0;
447 }
448
449 /**
450 * @internal
451 * call after asn_build_header to verify result.
452 *
453 * @param str error string
454 * @param pkt packet to check
455 * @param pkt_len length of the packet
456 * @param typedlen length of the type
457 *
458 * @return 0 on success 1 on error
459 */
460 static
461 int
_asn_realloc_build_header_check(const char * str,u_char ** pkt,const size_t * pkt_len,size_t typedlen)462 _asn_realloc_build_header_check(const char *str,
463 u_char ** pkt,
464 const size_t * pkt_len, size_t typedlen)
465 {
466 char ebuf[128];
467
468 if (pkt == NULL || *pkt == NULL) {
469 /*
470 * Error message is set.
471 */
472 return 1;
473 }
474
475 if (*pkt_len < typedlen) {
476 snprintf(ebuf, sizeof(ebuf),
477 "%s: bad header, length too short: %lu < %lu", str,
478 (unsigned long)*pkt_len, (unsigned long)typedlen);
479 ebuf[ sizeof(ebuf)-1 ] = 0;
480 ERROR_MSG(ebuf);
481 return 1;
482 }
483 return 0;
484 }
485
486 /**
487 * @internal
488 * checks the incoming packet for validity and returns its size or 0
489 *
490 * @param pkt The packet
491 * @param len The length to check
492 *
493 * @return The size of the packet if valid; 0 otherwise
494 */
495 int
asn_check_packet(u_char * pkt,size_t len)496 asn_check_packet(u_char * pkt, size_t len)
497 {
498 u_long asn_length;
499
500 if (len < 2)
501 return 0; /* always too short */
502
503 if (*pkt != (u_char) (ASN_SEQUENCE | ASN_CONSTRUCTOR))
504 return -1; /* wrong type */
505
506 if (*(pkt + 1) & 0x80) {
507 /*
508 * long length
509 */
510 if ((int) len < (int) (*(pkt + 1) & ~0x80) + 2)
511 return 0; /* still to short, incomplete length */
512 if (NULL == asn_parse_length(pkt + 1, &asn_length))
513 return 0; /* propagate error from asn_parse_length() */
514 return (asn_length + 2 + (*(pkt + 1) & ~0x80));
515 } else {
516 /*
517 * short length
518 */
519 return (*(pkt + 1) + 2);
520 }
521 }
522
523 static
524 int
_asn_bitstring_check(const char * str,size_t asn_length,u_char datum)525 _asn_bitstring_check(const char *str, size_t asn_length, u_char datum)
526 {
527 char ebuf[128];
528
529 if (asn_length < 1) {
530 snprintf(ebuf, sizeof(ebuf),
531 "%s: length %d too small", str, (int) asn_length);
532 ebuf[ sizeof(ebuf)-1 ] = 0;
533 ERROR_MSG(ebuf);
534 return 1;
535 }
536 /*
537 * if (datum > 7){
538 * sprintf(ebuf,"%s: datum %d >7: too large", str, (int)(datum));
539 * ERROR_MSG(ebuf);
540 * return 1;
541 * }
542 */
543 return 0;
544 }
545
546 /**
547 * @internal
548 * asn_parse_int - pulls a long out of an int type.
549 *
550 * On entry, datalength is input as the number of valid bytes following
551 * "data". On exit, it is returned as the number of valid bytes
552 * following the end of this object.
553 *
554 * Returns a pointer to the first byte past the end
555 * of this object (i.e. the start of the next object).
556 * Returns NULL on any error.
557 *
558 * @param data IN - pointer to start of object
559 * @param datalength IN/OUT - number of valid bytes left in buffer
560 * @param type OUT - asn type of object
561 * @param intp IN/OUT - pointer to start of output buffer
562 * @param intsize IN - size of output buffer
563 *
564 * @return pointer to the first byte past the end
565 * of this object (i.e. the start of the next object) Returns NULL on any error
566 */
567 u_char *
asn_parse_int(u_char * data,size_t * datalength,u_char * type,long * intp,size_t intsize)568 asn_parse_int(u_char * data,
569 size_t * datalength,
570 u_char * type, long *intp, size_t intsize)
571 {
572 /*
573 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
574 */
575 static const char *errpre = "parse int";
576 register u_char *bufp = data;
577 u_long asn_length;
578 int i;
579 union {
580 long l;
581 unsigned char b[sizeof(long)];
582 } value;
583
584 if (NULL == data || NULL == datalength || NULL == type || NULL == intp) {
585 ERROR_MSG("parse int: NULL pointer");
586 return NULL;
587 }
588
589 if (intsize != sizeof(long)) {
590 _asn_size_err(errpre, intsize, sizeof(long));
591 return NULL;
592 }
593
594 /** need at least 2 bytes to work with: type, length (which might be 0) */
595 if (*datalength < 2) {
596 _asn_short_err(errpre, *datalength, 2);
597 return NULL;
598 }
599
600 *type = *bufp++;
601 if (*type != ASN_INTEGER) {
602 _asn_type_err(errpre, *type);
603 return NULL;
604 }
605
606 bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
607 if (NULL == bufp) {
608 _asn_short_err(errpre, *datalength - 1, asn_length);
609 return NULL;
610 }
611
612 if ((size_t) asn_length > intsize || (int) asn_length == 0) {
613 _asn_length_err(errpre, (size_t) asn_length, intsize);
614 return NULL;
615 }
616
617 *datalength -= (int) asn_length + (bufp - data);
618
619 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
620
621 memset(&value.b, *bufp & 0x80 ? 0xff : 0, sizeof(value.b));
622 if (NETSNMP_BIGENDIAN) {
623 for (i = sizeof(long) - asn_length; asn_length--; i++)
624 value.b[i] = *bufp++;
625 } else {
626 for (i = asn_length - 1; asn_length--; i--)
627 value.b[i] = *bufp++;
628 }
629
630 CHECK_OVERFLOW_S(value.l, 1);
631
632 DEBUGMSG(("dumpv_recv", " Integer:\t%ld (0x%.2lX)\n", value.l, value.l));
633
634 *intp = value.l;
635 return bufp;
636 }
637
638
639 /**
640 * @internal
641 * asn_parse_unsigned_int - pulls an unsigned long out of an ASN int type.
642 *
643 * On entry, datalength is input as the number of valid bytes following
644 * "data". On exit, it is returned as the number of valid bytes
645 * following the end of this object.
646 *
647 * Returns a pointer to the first byte past the end
648 * of this object (i.e. the start of the next object).
649 * Returns NULL on any error.
650 *
651 * @param data IN - pointer to start of object
652 * @param datalength IN/OUT - number of valid bytes left in buffer
653 * @param type OUT - asn type of object
654 * @param intp IN/OUT - pointer to start of output buffer
655 * @param intsize IN - size of output buffer
656 *
657 * @return pointer to the first byte past the end
658 * of this object (i.e. the start of the next object) Returns NULL on any error
659 */
660 u_char *
asn_parse_unsigned_int(u_char * data,size_t * datalength,u_char * type,u_long * intp,size_t intsize)661 asn_parse_unsigned_int(u_char * data,
662 size_t * datalength,
663 u_char * type, u_long * intp, size_t intsize)
664 {
665 /*
666 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
667 */
668 static const char *errpre = "parse uint";
669 register u_char *bufp = data;
670 u_long asn_length;
671 register u_long value = 0;
672
673 if (NULL == data || NULL == datalength || NULL == type || NULL == intp) {
674 ERROR_MSG("parse uint: NULL pointer");
675 return NULL;
676 }
677
678 if (intsize != sizeof(long)) {
679 _asn_size_err(errpre, intsize, sizeof(long));
680 return NULL;
681 }
682
683 /** need at least 2 bytes to work with: type, length (which might be 0) */
684 if (*datalength < 2) {
685 _asn_short_err(errpre, *datalength, 2);
686 return NULL;
687 }
688
689 *type = *bufp++;
690 if (*type != ASN_COUNTER && *type != ASN_GAUGE && *type != ASN_TIMETICKS
691 && *type != ASN_UINTEGER) {
692 _asn_type_err(errpre, *type);
693 return NULL;
694 }
695
696 bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
697 if (NULL == bufp) {
698 _asn_short_err(errpre, *datalength - 1, asn_length);
699 return NULL;
700 }
701
702 if ((asn_length > (intsize + 1)) || ((int) asn_length == 0) ||
703 ((asn_length == intsize + 1) && *bufp != 0x00)) {
704 _asn_length_err(errpre, (size_t) asn_length, intsize);
705 return NULL;
706 }
707 *datalength -= (int) asn_length + (bufp - data);
708
709 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
710
711 while (asn_length--)
712 value = (value << 8) | *bufp++;
713
714 CHECK_OVERFLOW_U(value,2);
715
716 DEBUGMSG(("dumpv_recv", " UInteger:\t%ld (0x%.2lX)\n", value, value));
717
718 *intp = value;
719 return bufp;
720 }
721
722
723 /**
724 * @internal
725 * asn_build_int - builds an ASN object containing an integer.
726 *
727 * On entry, datalength is input as the number of valid bytes following
728 * "data". On exit, it is returned as the number of valid bytes
729 * following the end of this object.
730 *
731 * Returns a pointer to the first byte past the end
732 * of this object (i.e. the start of the next object).
733 * Returns NULL on any error.
734 *
735 *
736 * @param data IN - pointer to start of output buffer
737 * @param datalength IN/OUT - number of valid bytes left in buffer
738 * @param type IN - asn type of objec
739 * @param intp IN - pointer to start of long integer
740 * @param intsize IN - size of input buffer
741 *
742 * @return Returns a pointer to the first byte past the end
743 * of this object (i.e. the start of the next object).
744 * Returns NULL on any error.
745 */
746 u_char *
asn_build_int(u_char * data,size_t * datalength,u_char type,const long * intp,size_t intsize)747 asn_build_int(u_char * data,
748 size_t * datalength, u_char type, const long *intp, size_t intsize)
749 {
750 /*
751 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
752 */
753 static const char *errpre = "build int";
754 register long integer;
755 register u_long mask;
756 u_char *initdatap = data;
757
758 if (intsize != sizeof(long)) {
759 _asn_size_err(errpre, intsize, sizeof(long));
760 return NULL;
761 }
762 integer = *intp;
763 CHECK_OVERFLOW_S(integer,3);
764 /*
765 * Truncate "unnecessary" bytes off of the most significant end of this
766 * 2's complement integer. There should be no sequence of 9
767 * consecutive 1's or 0's at the most significant end of the
768 * integer.
769 */
770 mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
771 /*
772 * mask is 0xFF800000 on a big-endian machine
773 */
774 while ((((integer & mask) == 0) || ((integer & mask) == mask))
775 && intsize > 1) {
776 intsize--;
777 integer <<= 8;
778 }
779 data = asn_build_header(data, datalength, type, intsize);
780 if (_asn_build_header_check(errpre, data, *datalength, intsize))
781 return NULL;
782
783 *datalength -= intsize;
784 mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
785 /*
786 * mask is 0xFF000000 on a big-endian machine
787 */
788 while (intsize--) {
789 *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
790 integer <<= 8;
791 }
792 DEBUGDUMPSETUP("send", initdatap, data - initdatap);
793 DEBUGMSG(("dumpv_send", " Integer:\t%ld (0x%.2lX)\n", *intp, *intp));
794 return data;
795 }
796
797
798
799 /**
800 * @internal
801 * asn_build_unsigned_int - builds an ASN object containing an integer.
802 *
803 * On entry, datalength is input as the number of valid bytes following
804 * "data". On exit, it is returned as the number of valid bytes
805 * following the end of this object.
806 *
807 * Returns a pointer to the first byte past the end
808 * of this object (i.e. the start of the next object).
809 * Returns NULL on any error.
810 *
811 *
812 * @param data IN - pointer to start of output buffer
813 * @param datalength IN/OUT - number of valid bytes left in buffer
814 * @param type IN - asn type of objec
815 * @param intp IN - pointer to start of long integer
816 * @param intsize IN - size of input buffer
817 *
818 * @return Returns a pointer to the first byte past the end
819 * of this object (i.e. the start of the next object).
820 * Returns NULL on any error.
821 */
822 u_char *
asn_build_unsigned_int(u_char * data,size_t * datalength,u_char type,const u_long * intp,size_t intsize)823 asn_build_unsigned_int(u_char * data,
824 size_t * datalength,
825 u_char type, const u_long * intp, size_t intsize)
826 {
827 /*
828 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
829 */
830 static const char *errpre = "build uint";
831 register u_long integer;
832 register u_long mask;
833 int add_null_byte = 0;
834 u_char *initdatap = data;
835
836 if (intsize != sizeof(long)) {
837 _asn_size_err(errpre, intsize, sizeof(long));
838 return NULL;
839 }
840 integer = *intp;
841 CHECK_OVERFLOW_U(integer,4);
842
843 mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
844 /*
845 * mask is 0xFF000000 on a big-endian machine
846 */
847 if ((u_char) ((integer & mask) >> (8 * (sizeof(long) - 1))) & 0x80) {
848 /*
849 * if MSB is set
850 */
851 add_null_byte = 1;
852 intsize++;
853 } else {
854 /*
855 * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer.
856 * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the
857 * integer.
858 */
859 mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
860 /*
861 * mask is 0xFF800000 on a big-endian machine
862 */
863 while ((((integer & mask) == 0) || ((integer & mask) == mask))
864 && intsize > 1) {
865 intsize--;
866 integer <<= 8;
867 }
868 }
869 data = asn_build_header(data, datalength, type, intsize);
870 if (_asn_build_header_check(errpre, data, *datalength, intsize))
871 return NULL;
872
873 *datalength -= intsize;
874 if (add_null_byte == 1) {
875 *data++ = '\0';
876 intsize--;
877 }
878 mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
879 /*
880 * mask is 0xFF000000 on a big-endian machine
881 */
882 while (intsize--) {
883 *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
884 integer <<= 8;
885 }
886 DEBUGDUMPSETUP("send", initdatap, data - initdatap);
887 DEBUGMSG(("dumpv_send", " UInteger:\t%ld (0x%.2lX)\n", *intp, *intp));
888 return data;
889 }
890
891
892 /**
893 * @internal
894 * asn_parse_string - pulls an octet string out of an ASN octet string type.
895 *
896 * On entry, datalength is input as the number of valid bytes following
897 * "data". On exit, it is returned as the number of valid bytes
898 * following the beginning of the next object.
899 *
900 * "string" is filled with the octet string.
901 * ASN.1 octet string ::= primstring | cmpdstring
902 * primstring ::= 0x04 asnlength byte {byte}*
903 * cmpdstring ::= 0x24 asnlength string {string}*
904 *
905 * Returns a pointer to the first byte past the end
906 * of this object (i.e. the start of the next object).
907 * Returns NULL on any error.
908 *
909 * @param data IN - pointer to start of object
910 * @param datalength IN/OUT - number of valid bytes left in buffer
911 * @param type OUT - asn type of object
912 * @param string IN/OUT - pointer to start of output buffer
913 * @param strlength IN/OUT - size of output buffer
914 *
915 * @return Returns a pointer to the first byte past the end
916 * of this object (i.e. the start of the next object).
917 * Returns NULL on any error.
918 */
919
920 u_char *
asn_parse_string(u_char * data,size_t * datalength,u_char * type,u_char * str,size_t * strlength)921 asn_parse_string(u_char * data,
922 size_t * datalength,
923 u_char * type, u_char * str, size_t * strlength)
924 {
925 static const char *errpre = "parse string";
926 u_char *bufp = data;
927 u_long asn_length;
928
929 if (NULL == data || NULL == datalength || NULL == type || NULL == str ||
930 NULL == strlength) {
931 ERROR_MSG("parse string: NULL pointer");
932 return NULL;
933 }
934
935 /** need at least 2 bytes to work with: type, length (which might be 0) */
936 if (*datalength < 2) {
937 _asn_short_err(errpre, *datalength, 2);
938 return NULL;
939 }
940
941 *type = *bufp++;
942 if (*type != ASN_OCTET_STR && *type != ASN_IPADDRESS && *type != ASN_OPAQUE
943 && *type != ASN_NSAP) {
944 _asn_type_err(errpre, *type);
945 return NULL;
946 }
947
948 bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
949 if (NULL == bufp) {
950 _asn_short_err(errpre, *datalength - 1, asn_length);
951 return NULL;
952 }
953
954 if (asn_length > *strlength) {
955 _asn_length_err(errpre, (size_t) asn_length, *strlength);
956 return NULL;
957 }
958
959 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
960
961 memmove(str, bufp, asn_length);
962 if (*strlength > asn_length)
963 str[asn_length] = 0;
964 *strlength = asn_length;
965 *datalength -= asn_length + (bufp - data);
966
967 DEBUGIF("dumpv_recv") {
968 u_char *buf = (u_char *) malloc(1 + asn_length);
969 size_t l = (buf != NULL) ? (1 + asn_length) : 0, ol = 0;
970
971 if (sprint_realloc_asciistring
972 (&buf, &l, &ol, 1, str, asn_length)) {
973 DEBUGMSG(("dumpv_recv", " String:\t%s\n", buf));
974 } else {
975 if (buf == NULL) {
976 DEBUGMSG(("dumpv_recv", " String:\t[TRUNCATED]\n"));
977 } else {
978 DEBUGMSG(("dumpv_recv", " String:\t%s [TRUNCATED]\n",
979 buf));
980 }
981 }
982 if (buf != NULL) {
983 free(buf);
984 }
985 }
986
987 return bufp + asn_length;
988 }
989
990
991 /**
992 * @internal
993 * asn_build_string - Builds an ASN octet string object containing the input string.
994 *
995 * On entry, datalength is input as the number of valid bytes following
996 * "data". On exit, it is returned as the number of valid bytes
997 * following the beginning of the next object.
998 *
999 * Returns a pointer to the first byte past the end
1000 * of this object (i.e. the start of the next object).
1001 * Returns NULL on any error.
1002 *
1003 * @param data IN - pointer to start of object
1004 * @param datalength IN/OUT - number of valid bytes left in buffer
1005 * @param type IN - asn type of object
1006 * @param string IN - pointer to start of input buffer
1007 * @param strlength IN - size of input buffer
1008 * @return Returns a pointer to the first byte past the end
1009 * of this object (i.e. the start of the next object).
1010 * Returns NULL on any error.
1011 */
1012
1013 u_char *
asn_build_string(u_char * data,size_t * datalength,u_char type,const u_char * str,size_t strlength)1014 asn_build_string(u_char * data,
1015 size_t * datalength,
1016 u_char type, const u_char * str, size_t strlength)
1017 {
1018 /*
1019 * ASN.1 octet string ::= primstring | cmpdstring
1020 * primstring ::= 0x04 asnlength byte {byte}*
1021 * cmpdstring ::= 0x24 asnlength string {string}*
1022 * This code will never send a compound string.
1023 */
1024 u_char *initdatap = data;
1025 data = asn_build_header(data, datalength, type, strlength);
1026 if (_asn_build_header_check
1027 ("build string", data, *datalength, strlength))
1028 return NULL;
1029
1030 if (strlength) {
1031 if (str == NULL) {
1032 memset(data, 0, strlength);
1033 } else {
1034 memmove(data, str, strlength);
1035 }
1036 }
1037 *datalength -= strlength;
1038 DEBUGDUMPSETUP("send", initdatap, data - initdatap + strlength);
1039 DEBUGIF("dumpv_send") {
1040 u_char *buf = (u_char *) malloc(1 + strlength);
1041 size_t l = (buf != NULL) ? (1 + strlength) : 0, ol = 0;
1042
1043 if (sprint_realloc_asciistring(&buf, &l, &ol, 1,
1044 str ? str : (const u_char *)"",
1045 strlength)) {
1046 DEBUGMSG(("dumpv_send", " String:\t%s\n", buf));
1047 } else {
1048 if (buf == NULL) {
1049 DEBUGMSG(("dumpv_send", " String:\t[TRUNCATED]\n"));
1050 } else {
1051 DEBUGMSG(("dumpv_send", " String:\t%s [TRUNCATED]\n",
1052 buf));
1053 }
1054 }
1055 if (buf != NULL) {
1056 free(buf);
1057 }
1058 }
1059 return data + strlength;
1060 }
1061
1062
1063
1064 /**
1065 * @internal
1066 * asn_parse_header - interprets the ID and length of the current object.
1067 *
1068 * On entry, datalength is input as the number of valid bytes following
1069 * "data". On exit, it is returned as the number of valid bytes
1070 * in this object following the id and length.
1071 *
1072 * Returns a pointer to the first byte of the contents of this object.
1073 * Returns NULL on any error.
1074 *
1075 *
1076 * @param data IN - pointer to start of object
1077 * @param datalength IN/OUT - number of valid bytes left in buffer
1078 * @param type OUT - asn type of object
1079 * @return Returns a pointer to the first byte of the contents of this object.
1080 * Returns NULL on any error.
1081 *
1082 */
1083 u_char *
asn_parse_header(u_char * data,size_t * datalength,u_char * type)1084 asn_parse_header(u_char * data, size_t * datalength, u_char * type)
1085 {
1086 register u_char *bufp;
1087 u_long asn_length = 0;
1088 const char *errpre = "parse header";
1089
1090 if (!data || !datalength || !type) {
1091 ERROR_MSG("parse header: NULL pointer");
1092 return NULL;
1093 }
1094
1095 /** need at least 2 bytes to work with: type, length (which might be 0) */
1096 if (*datalength < 2) {
1097 _asn_short_err(errpre, *datalength, 2);
1098 return NULL;
1099 }
1100
1101 bufp = data;
1102 /*
1103 * this only works on data types < 30, i.e. no extension octets
1104 */
1105 if (IS_EXTENSION_ID(*bufp)) {
1106 ERROR_MSG("can't process ID >= 30");
1107 return NULL;
1108 }
1109 *type = *bufp++;
1110
1111 bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1112 if (NULL == bufp) {
1113 _asn_short_err(errpre, *datalength - 1, asn_length);
1114 return NULL;
1115 }
1116
1117 #ifdef DUMP_PRINT_HEADERS
1118 DEBUGDUMPSETUP("recv", data, (bufp - data));
1119 DEBUGMSG(("dumpv_recv", " Header: 0x%.2X, len = %d (0x%X)\n", *data,
1120 asn_length, asn_length));
1121 #else
1122 /*
1123 * DEBUGMSGHEXTLI(("recv",data,(bufp-data)));
1124 * DEBUGMSG(("dumpH_recv","\n"));
1125 */
1126 #endif
1127
1128 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1129
1130 if ((asn_length > 2) && (*type == ASN_OPAQUE) && (*bufp == ASN_OPAQUE_TAG1)) {
1131
1132 /*
1133 * check if 64-but counter
1134 */
1135 switch (*(bufp + 1)) {
1136 case ASN_OPAQUE_COUNTER64:
1137 case ASN_OPAQUE_U64:
1138 case ASN_OPAQUE_FLOAT:
1139 case ASN_OPAQUE_DOUBLE:
1140 case ASN_OPAQUE_I64:
1141 *type = *(bufp + 1);
1142 break;
1143
1144 default:
1145 /*
1146 * just an Opaque
1147 */
1148 *datalength = (int) asn_length;
1149 return bufp;
1150 }
1151 /*
1152 * value is encoded as special format
1153 */
1154 *datalength = (int) asn_length;
1155 bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
1156 if (NULL == bufp) {
1157 _asn_short_err("parse opaque header", *datalength - 2, asn_length);
1158 return NULL;
1159 }
1160 }
1161 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
1162
1163 *datalength = (int) asn_length;
1164
1165 return bufp;
1166 }
1167
1168 /**
1169 * @internal
1170 * same as asn_parse_header with test for expected type
1171 *
1172 * @see asn_parse_header
1173 *
1174 * @param data IN - pointer to start of object
1175 * @param datalength IN/OUT - number of valid bytes left in buffer
1176 * @param type OUT - asn type of object
1177 * @param expected_type IN expected type
1178 * @return Returns a pointer to the first byte of the contents of this object.
1179 * Returns NULL on any error.
1180 *
1181 */
1182 u_char *
asn_parse_sequence(u_char * data,size_t * datalength,u_char * type,u_char expected_type,const char * estr)1183 asn_parse_sequence(u_char * data, size_t * datalength, u_char * type, u_char expected_type, /* must be this type */
1184 const char *estr)
1185 { /* error message prefix */
1186 data = asn_parse_header(data, datalength, type);
1187 if (data && (*type != expected_type)) {
1188 char ebuf[128];
1189 snprintf(ebuf, sizeof(ebuf),
1190 "%s header type %02X: s/b %02X", estr,
1191 (u_char) * type, (u_char) expected_type);
1192 ebuf[ sizeof(ebuf)-1 ] = 0;
1193 ERROR_MSG(ebuf);
1194 return NULL;
1195 }
1196 return data;
1197 }
1198
1199
1200
1201 /**
1202 * @internal
1203 * asn_build_header - builds an ASN header for an object with the ID and
1204 * length specified.
1205 *
1206 * On entry, datalength is input as the number of valid bytes following
1207 * "data". On exit, it is returned as the number of valid bytes
1208 * in this object following the id and length.
1209 *
1210 * This only works on data types < 30, i.e. no extension octets.
1211 * The maximum length is 0xFFFF;
1212 *
1213 * Returns a pointer to the first byte of the contents of this object.
1214 * Returns NULL on any error.
1215 *
1216 * @param data IN - pointer to start of object
1217 * @param datalength IN/OUT - number of valid bytes left in buffer
1218 * @param type IN - asn type of object
1219 * @param length IN - length of object
1220 * @return Returns a pointer to the first byte of the contents of this object.
1221 * Returns NULL on any error.
1222 */
1223 u_char *
asn_build_header(u_char * data,size_t * datalength,u_char type,size_t length)1224 asn_build_header(u_char * data,
1225 size_t * datalength, u_char type, size_t length)
1226 {
1227 char ebuf[128];
1228
1229 if (*datalength < 1) {
1230 snprintf(ebuf, sizeof(ebuf),
1231 "bad header length < 1 :%lu, %lu",
1232 (unsigned long)*datalength, (unsigned long)length);
1233 ebuf[ sizeof(ebuf)-1 ] = 0;
1234 ERROR_MSG(ebuf);
1235 return NULL;
1236 }
1237 *data++ = type;
1238 (*datalength)--;
1239 return asn_build_length(data, datalength, length);
1240 }
1241
1242 /**
1243 * @internal
1244 * asn_build_sequence - builds an ASN header for a sequence with the ID and
1245 *
1246 * length specified.
1247 * On entry, datalength is input as the number of valid bytes following
1248 * "data". On exit, it is returned as the number of valid bytes
1249 * in this object following the id and length.
1250 *
1251 * This only works on data types < 30, i.e. no extension octets.
1252 * The maximum length is 0xFFFF;
1253 *
1254 * Returns a pointer to the first byte of the contents of this object.
1255 * Returns NULL on any error.
1256 *
1257 * @param data IN - pointer to start of object
1258 * @param datalength IN/OUT - number of valid bytes left in buffer
1259 * @param type IN - asn type of object
1260 * @param length IN - length of object
1261 *
1262 * @return Returns a pointer to the first byte of the contents of this object.
1263 * Returns NULL on any error.
1264 */
1265 u_char *
asn_build_sequence(u_char * data,size_t * datalength,u_char type,size_t length)1266 asn_build_sequence(u_char * data,
1267 size_t * datalength, u_char type, size_t length)
1268 {
1269 static const char *errpre = "build seq";
1270 char ebuf[128];
1271
1272 if (*datalength < 4) {
1273 snprintf(ebuf, sizeof(ebuf),
1274 "%s: length %d < 4: PUNT", errpre,
1275 (int) *datalength);
1276 ebuf[ sizeof(ebuf)-1 ] = 0;
1277 ERROR_MSG(ebuf);
1278 return NULL;
1279 }
1280 *datalength -= 4;
1281 *data++ = type;
1282 *data++ = (u_char) (0x02 | ASN_LONG_LEN);
1283 *data++ = (u_char) ((length >> 8) & 0xFF);
1284 *data++ = (u_char) (length & 0xFF);
1285 return data;
1286 }
1287
1288 /**
1289 * @internal
1290 * asn_parse_length - interprets the length of the current object.
1291 *
1292 * On exit, length contains the value of this length field.
1293 *
1294 * Returns a pointer to the first byte after this length
1295 * field (aka: the start of the data field).
1296 * Returns NULL on any error.
1297 *
1298 * @param data IN - pointer to start of length field
1299 * @param length OUT - value of length field
1300 *
1301 * @return Returns a pointer to the first byte after this length
1302 * field (aka: the start of the data field).
1303 * Returns NULL on any error.
1304 *
1305 * WARNING: this function does not know the length of the data
1306 * buffer, so it can go past the end of a short buffer.
1307 */
1308 u_char *
asn_parse_length(u_char * data,u_long * length)1309 asn_parse_length(u_char * data, u_long * length)
1310 {
1311 static const char *errpre = "parse length";
1312 char ebuf[128];
1313 register u_char lengthbyte;
1314
1315 if (!data || !length) {
1316 ERROR_MSG("parse length: NULL pointer");
1317 return NULL;
1318 }
1319 lengthbyte = *data;
1320
1321 if (lengthbyte & ASN_LONG_LEN) {
1322 lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */
1323 if (lengthbyte == 0) {
1324 snprintf(ebuf, sizeof(ebuf),
1325 "%s: indefinite length not supported", errpre);
1326 ebuf[ sizeof(ebuf)-1 ] = 0;
1327 ERROR_MSG(ebuf);
1328 return NULL;
1329 }
1330 if (lengthbyte > sizeof(long)) {
1331 snprintf(ebuf, sizeof(ebuf),
1332 "%s: data length %d > %lu not supported", errpre,
1333 lengthbyte, (unsigned long)sizeof(long));
1334 ebuf[ sizeof(ebuf)-1 ] = 0;
1335 ERROR_MSG(ebuf);
1336 return NULL;
1337 }
1338 data++;
1339 *length = 0; /* protect against short lengths */
1340 while (lengthbyte--) {
1341 *length <<= 8;
1342 *length |= *data++;
1343 }
1344 if ((long) *length < 0) {
1345 snprintf(ebuf, sizeof(ebuf),
1346 "%s: negative data length %ld\n", errpre,
1347 (long) *length);
1348 ebuf[ sizeof(ebuf)-1 ] = 0;
1349 ERROR_MSG(ebuf);
1350 return NULL;
1351 }
1352 return data;
1353 } else { /* short asnlength */
1354 *length = (long) lengthbyte;
1355 return data + 1;
1356 }
1357 }
1358
1359 /**
1360 * @internal
1361 * asn_build_length - builds an ASN header for a length with
1362 * length specified.
1363 *
1364 * On entry, datalength is input as the number of valid bytes following
1365 * "data". On exit, it is returned as the number of valid bytes
1366 * in this object following the length.
1367 *
1368 *
1369 * Returns a pointer to the first byte of the contents of this object.
1370 * Returns NULL on any error.
1371 *
1372 * @param data IN - pointer to start of object
1373 * @param datalength IN/OUT - number of valid bytes left in buffer
1374 * @param length IN - length of object
1375 *
1376 * @return Returns a pointer to the first byte of the contents of this object.
1377 * Returns NULL on any error.
1378 */
1379 u_char *
asn_build_length(u_char * data,size_t * datalength,size_t length)1380 asn_build_length(u_char * data, size_t * datalength, size_t length)
1381 {
1382 static const char *errpre = "build length";
1383 char ebuf[128];
1384
1385 u_char *start_data = data;
1386
1387 /*
1388 * no indefinite lengths sent
1389 */
1390 if (length < 0x80) {
1391 if (*datalength < 1) {
1392 snprintf(ebuf, sizeof(ebuf),
1393 "%s: bad length < 1 :%lu, %lu", errpre,
1394 (unsigned long)*datalength, (unsigned long)length);
1395 ebuf[ sizeof(ebuf)-1 ] = 0;
1396 ERROR_MSG(ebuf);
1397 return NULL;
1398 }
1399 *data++ = (u_char) length;
1400 } else if (length <= 0xFF) {
1401 if (*datalength < 2) {
1402 snprintf(ebuf, sizeof(ebuf),
1403 "%s: bad length < 2 :%lu, %lu", errpre,
1404 (unsigned long)*datalength, (unsigned long)length);
1405 ebuf[ sizeof(ebuf)-1 ] = 0;
1406 ERROR_MSG(ebuf);
1407 return NULL;
1408 }
1409 *data++ = (u_char) (0x01 | ASN_LONG_LEN);
1410 *data++ = (u_char) length;
1411 } else { /* 0xFF < length <= 0xFFFF */
1412 if (*datalength < 3) {
1413 snprintf(ebuf, sizeof(ebuf),
1414 "%s: bad length < 3 :%lu, %lu", errpre,
1415 (unsigned long)*datalength, (unsigned long)length);
1416 ebuf[ sizeof(ebuf)-1 ] = 0;
1417 ERROR_MSG(ebuf);
1418 return NULL;
1419 }
1420 *data++ = (u_char) (0x02 | ASN_LONG_LEN);
1421 *data++ = (u_char) ((length >> 8) & 0xFF);
1422 *data++ = (u_char) (length & 0xFF);
1423 }
1424 *datalength -= (data - start_data);
1425 return data;
1426
1427 }
1428
1429 /**
1430 * @internal
1431 * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
1432 *
1433 * On entry, datalength is input as the number of valid bytes following
1434 * "data". On exit, it is returned as the number of valid bytes
1435 * following the beginning of the next object.
1436 *
1437 * "objid" is filled with the object identifier.
1438 *
1439 * Returns a pointer to the first byte past the end
1440 * of this object (i.e. the start of the next object).
1441 * Returns NULL on any error.
1442 *
1443 * @param data IN - pointer to start of object
1444 * @param datalength IN/OUT - number of valid bytes left in buffer
1445 * @param type OUT - asn type of object
1446 * @param objid IN/OUT - pointer to start of output buffer
1447 * @param objidlength IN/OUT - number of sub-id's in objid
1448 *
1449 * @return Returns a pointer to the first byte past the end
1450 * of this object (i.e. the start of the next object).
1451 * Returns NULL on any error.
1452 *
1453 */
1454 u_char *
asn_parse_objid(u_char * data,size_t * datalength,u_char * type,oid * objid,size_t * objidlength)1455 asn_parse_objid(u_char * data,
1456 size_t * datalength,
1457 u_char * type, oid * objid, size_t * objidlength)
1458 {
1459 static const char *errpre = "parse objid";
1460 /*
1461 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
1462 * subidentifier ::= {leadingbyte}* lastbyte
1463 * leadingbyte ::= 1 7bitvalue
1464 * lastbyte ::= 0 7bitvalue
1465 */
1466 register u_char *bufp = data;
1467 register oid *oidp = objid + 1;
1468 register u_long subidentifier;
1469 register long length;
1470 u_long asn_length;
1471 size_t original_length = *objidlength;
1472
1473 if (NULL == data || NULL == datalength || NULL == type || NULL == objid) {
1474 ERROR_MSG("parse objid: NULL pointer");
1475 return NULL;
1476 }
1477
1478 /** need at least 2 bytes to work with: type, length (which might be 0) */
1479 if (*datalength < 2) {
1480 _asn_short_err(errpre, *datalength, 2);
1481 return NULL;
1482 }
1483
1484 *type = *bufp++;
1485 if (*type != ASN_OBJECT_ID) {
1486 _asn_type_err(errpre, *type);
1487 return NULL;
1488 }
1489 bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1490 if (NULL == bufp) {
1491 _asn_short_err(errpre, *datalength - 1, asn_length);
1492 return NULL;
1493 }
1494
1495 *datalength -= (int) asn_length + (bufp - data);
1496
1497 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
1498
1499 /*
1500 * Handle invalid object identifier encodings of the form 06 00 robustly
1501 */
1502 if (asn_length == 0)
1503 objid[0] = objid[1] = 0;
1504
1505 length = asn_length;
1506 (*objidlength)--; /* account for expansion of first byte */
1507
1508 while (length > 0 && (*objidlength)-- > 0) {
1509 subidentifier = 0;
1510 do { /* shift and add in low order 7 bits */
1511 subidentifier =
1512 (subidentifier << 7) + (*(u_char *) bufp & ~ASN_BIT8);
1513 length--;
1514 } while ((*(u_char *) bufp++ & ASN_BIT8) && (length > 0)); /* last byte has high bit clear */
1515
1516 if (length == 0) {
1517 u_char *last_byte = bufp - 1;
1518 if (*last_byte & ASN_BIT8) {
1519 /* last byte has high bit set -> wrong BER encoded OID */
1520 ERROR_MSG("subidentifier syntax error");
1521 return NULL;
1522 }
1523 }
1524 #if defined(EIGHTBIT_SUBIDS) || (SIZEOF_LONG != 4)
1525 if (subidentifier > MAX_SUBID) {
1526 ERROR_MSG("subidentifier too large");
1527 return NULL;
1528 }
1529 #endif
1530 *oidp++ = (oid) subidentifier;
1531 }
1532
1533 if (length || oidp < objid + 1) {
1534 ERROR_MSG("OID length exceeds buffer size");
1535 *objidlength = original_length;
1536 return NULL;
1537 }
1538
1539 /*
1540 * The first two subidentifiers are encoded into the first component
1541 * with the value (X * 40) + Y, where:
1542 * X is the value of the first subidentifier.
1543 * Y is the value of the second subidentifier.
1544 */
1545 subidentifier = oidp - objid >= 2 ? objid[1] : 0;
1546 if (subidentifier == 0x2B) {
1547 objid[0] = 1;
1548 objid[1] = 3;
1549 } else {
1550 if (subidentifier < 40) {
1551 objid[0] = 0;
1552 objid[1] = subidentifier;
1553 } else if (subidentifier < 80) {
1554 objid[0] = 1;
1555 objid[1] = subidentifier - 40;
1556 } else {
1557 objid[0] = 2;
1558 objid[1] = subidentifier - 80;
1559 }
1560 }
1561
1562 *objidlength = (int) (oidp - objid);
1563
1564 DEBUGMSG(("dumpv_recv", " ObjID: "));
1565 DEBUGMSGOID(("dumpv_recv", objid, *objidlength));
1566 DEBUGMSG(("dumpv_recv", "\n"));
1567 return bufp;
1568 }
1569
1570 /**
1571 * @internal
1572 * asn_build_objid - Builds an ASN object identifier object containing the
1573 * input string.
1574 *
1575 * On entry, datalength is input as the number of valid bytes following
1576 * "data". On exit, it is returned as the number of valid bytes
1577 * following the beginning of the next object.
1578 *
1579 * Returns a pointer to the first byte past the end
1580 * of this object (i.e. the start of the next object).
1581 * Returns NULL on any error.
1582 *
1583 * @param data IN - pointer to start of object
1584 * @param datalength IN/OUT - number of valid bytes left in buffer
1585 * @param type IN - asn type of object
1586 * @param objid IN - pointer to start of input buffer
1587 * @param objidlength IN - number of sub-id's in objid
1588 *
1589 * @return Returns a pointer to the first byte past the end
1590 * of this object (i.e. the start of the next object).
1591 * Returns NULL on any error.
1592 */
1593 u_char *
asn_build_objid(u_char * data,size_t * datalength,u_char type,oid * objid,size_t objidlength)1594 asn_build_objid(u_char * data,
1595 size_t * datalength,
1596 u_char type, oid * objid, size_t objidlength)
1597 {
1598 /*
1599 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
1600 * subidentifier ::= {leadingbyte}* lastbyte
1601 * leadingbyte ::= 1 7bitvalue
1602 * lastbyte ::= 0 7bitvalue
1603 */
1604 size_t asnlength;
1605 register oid *op = objid;
1606 u_char objid_size[MAX_OID_LEN];
1607 register u_long objid_val;
1608 u_long first_objid_val;
1609 register int i;
1610 u_char *initdatap = data;
1611
1612 /*
1613 * check if there are at least 2 sub-identifiers
1614 */
1615 if (objidlength == 0) {
1616 /*
1617 * there are not, so make OID have two with value of zero
1618 */
1619 objid_val = 0;
1620 objidlength = 2;
1621 } else if (objid[0] > 2) {
1622 ERROR_MSG("build objid: bad first subidentifier");
1623 return NULL;
1624 } else if (objidlength == 1) {
1625 /*
1626 * encode the first value
1627 */
1628 objid_val = (op[0] * 40);
1629 objidlength = 2;
1630 op++;
1631 } else {
1632 /*
1633 * combine the first two values
1634 */
1635 if ((op[1] > 40) &&
1636 (op[0] < 2)) {
1637 ERROR_MSG("build objid: bad second subidentifier");
1638 return NULL;
1639 }
1640 objid_val = (op[0] * 40) + op[1];
1641 op += 2;
1642 }
1643 first_objid_val = objid_val;
1644
1645 /*
1646 * ditch illegal calls now
1647 */
1648 if (objidlength > MAX_OID_LEN)
1649 return NULL;
1650
1651 /*
1652 * calculate the number of bytes needed to store the encoded value
1653 */
1654 for (i = 1, asnlength = 0;;) {
1655
1656 CHECK_OVERFLOW_U(objid_val,5);
1657 if (objid_val < (unsigned) 0x80) {
1658 objid_size[i] = 1;
1659 asnlength += 1;
1660 } else if (objid_val < (unsigned) 0x4000) {
1661 objid_size[i] = 2;
1662 asnlength += 2;
1663 } else if (objid_val < (unsigned) 0x200000) {
1664 objid_size[i] = 3;
1665 asnlength += 3;
1666 } else if (objid_val < (unsigned) 0x10000000) {
1667 objid_size[i] = 4;
1668 asnlength += 4;
1669 } else {
1670 objid_size[i] = 5;
1671 asnlength += 5;
1672 }
1673 i++;
1674 if (i >= (int) objidlength)
1675 break;
1676 objid_val = *op++; /* XXX - doesn't handle 2.X (X > 40) */
1677 }
1678
1679 /*
1680 * store the ASN.1 tag and length
1681 */
1682 data = asn_build_header(data, datalength, type, asnlength);
1683 if (_asn_build_header_check
1684 ("build objid", data, *datalength, asnlength))
1685 return NULL;
1686
1687 /*
1688 * store the encoded OID value
1689 */
1690 for (i = 1, objid_val = first_objid_val, op = objid + 2;
1691 i < (int) objidlength; i++) {
1692 if (i != 1)
1693 objid_val = (uint32_t)(*op++); /* already logged warning above */
1694 switch (objid_size[i]) {
1695 case 1:
1696 *data++ = (u_char) objid_val;
1697 break;
1698
1699 case 2:
1700 *data++ = (u_char) ((objid_val >> 7) | 0x80);
1701 *data++ = (u_char) (objid_val & 0x07f);
1702 break;
1703
1704 case 3:
1705 *data++ = (u_char) ((objid_val >> 14) | 0x80);
1706 *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80);
1707 *data++ = (u_char) (objid_val & 0x07f);
1708 break;
1709
1710 case 4:
1711 *data++ = (u_char) ((objid_val >> 21) | 0x80);
1712 *data++ = (u_char) ((objid_val >> 14 & 0x7f) | 0x80);
1713 *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80);
1714 *data++ = (u_char) (objid_val & 0x07f);
1715 break;
1716
1717 case 5:
1718 *data++ = (u_char) ((objid_val >> 28) | 0x80);
1719 *data++ = (u_char) ((objid_val >> 21 & 0x7f) | 0x80);
1720 *data++ = (u_char) ((objid_val >> 14 & 0x7f) | 0x80);
1721 *data++ = (u_char) ((objid_val >> 7 & 0x7f) | 0x80);
1722 *data++ = (u_char) (objid_val & 0x07f);
1723 break;
1724 }
1725 }
1726
1727 /*
1728 * return the length and data ptr
1729 */
1730 *datalength -= asnlength;
1731 DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1732 DEBUGMSG(("dumpv_send", " ObjID: "));
1733 DEBUGMSGOID(("dumpv_send", objid, objidlength));
1734 DEBUGMSG(("dumpv_send", "\n"));
1735 return data;
1736 }
1737
1738 /**
1739 * @internal
1740 * asn_parse_null - Interprets an ASN null type.
1741 *
1742 * On entry, datalength is input as the number of valid bytes following
1743 * "data". On exit, it is returned as the number of valid bytes
1744 * following the beginning of the next object.
1745 *
1746 * Returns a pointer to the first byte past the end
1747 * of this object (i.e. the start of the next object).
1748 * Returns NULL on any error.
1749 *
1750 * @param data IN - pointer to start of object
1751 * @param datalength IN/OUT - number of valid bytes left in buffer
1752 * @param type OUT - asn type of object
1753 * @return Returns a pointer to the first byte past the end
1754 * of this object (i.e. the start of the next object).
1755 * Returns NULL on any error.
1756 */
1757 u_char *
asn_parse_null(u_char * data,size_t * datalength,u_char * type)1758 asn_parse_null(u_char * data, size_t * datalength, u_char * type)
1759 {
1760 /*
1761 * ASN.1 null ::= 0x05 0x00
1762 */
1763 register u_char *bufp = data;
1764 u_long asn_length;
1765 static const char *errpre = "parse null";
1766
1767 if (NULL == data || NULL == datalength || NULL == type) {
1768 ERROR_MSG("parse null: NULL pointer");
1769 return NULL;
1770 }
1771
1772 /** need at least 2 bytes to work with: type, length (which should be 0) */
1773 if (*datalength < 2) {
1774 _asn_short_err(errpre, *datalength, 2);
1775 return NULL;
1776 }
1777
1778 *type = *bufp++;
1779 bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1780 if (NULL == bufp) {
1781 _asn_short_err(errpre, *datalength - 1, asn_length);
1782 return NULL;
1783 }
1784 if (asn_length != 0) {
1785 ERROR_MSG("parse null: malformed ASN.1 null");
1786 return NULL;
1787 }
1788
1789 *datalength -= (bufp - data);
1790
1791 DEBUGDUMPSETUP("recv", data, bufp - data);
1792 DEBUGMSG(("dumpv_recv", " NULL\n"));
1793
1794 return bufp + asn_length;
1795 }
1796
1797
1798 /**
1799 * @internal
1800 * asn_build_null - Builds an ASN null object.
1801 *
1802 * On entry, datalength is input as the number of valid bytes following
1803 * "data". On exit, it is returned as the number of valid bytes
1804 * following the beginning of the next object.
1805 *
1806 * Returns a pointer to the first byte past the end
1807 * of this object (i.e. the start of the next object).
1808 * Returns NULL on any error.
1809 *
1810 * @param data IN - pointer to start of object
1811 * @param datalength IN/OUT - number of valid bytes left in buffer
1812 * @param type IN - asn type of object
1813 * @retun Returns a pointer to the first byte past the end
1814 * of this object (i.e. the start of the next object).
1815 * Returns NULL on any error.
1816 *
1817 */
1818 u_char *
asn_build_null(u_char * data,size_t * datalength,u_char type)1819 asn_build_null(u_char * data, size_t * datalength, u_char type)
1820 {
1821 /*
1822 * ASN.1 null ::= 0x05 0x00
1823 */
1824 u_char *initdatap = data;
1825 data = asn_build_header(data, datalength, type, 0);
1826 DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1827 DEBUGMSG(("dumpv_send", " NULL\n"));
1828 return data;
1829 }
1830
1831 /**
1832 * @internal
1833 * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
1834 *
1835 * On entry, datalength is input as the number of valid bytes following
1836 * "data". On exit, it is returned as the number of valid bytes
1837 * following the beginning of the next object.
1838 *
1839 * "string" is filled with the bit string.
1840 *
1841 * Returns a pointer to the first byte past the end
1842 * of this object (i.e. the start of the next object).
1843 * Returns NULL on any error.
1844 *
1845 * @param data IN - pointer to start of object
1846 * @param datalength IN/OUT - number of valid bytes left in buffer
1847 * @param type OUT - asn type of object
1848 * @param string IN/OUT - pointer to start of output buffer
1849 * @param strlength IN/OUT - size of output buffer
1850 * @return Returns a pointer to the first byte past the end
1851 * of this object (i.e. the start of the next object).
1852 * Returns NULL on any error.
1853 */
1854 u_char *
asn_parse_bitstring(u_char * data,size_t * datalength,u_char * type,u_char * str,size_t * strlength)1855 asn_parse_bitstring(u_char * data,
1856 size_t * datalength,
1857 u_char * type, u_char * str, size_t * strlength)
1858 {
1859 /*
1860 * bitstring ::= 0x03 asnlength unused {byte}*
1861 */
1862 static const char *errpre = "parse bitstring";
1863 register u_char *bufp = data;
1864 u_long asn_length;
1865
1866 if (NULL == data || NULL == datalength || NULL == type ||
1867 NULL == str || NULL == strlength) {
1868 ERROR_MSG("parse bitstring: NULL pointer");
1869 return NULL;
1870 }
1871
1872 /** need at least 2 bytes to work with: type, length (which might be 0) */
1873 if (*datalength < 2) {
1874 _asn_short_err(errpre, *datalength, 2);
1875 return NULL;
1876 }
1877
1878 *type = *bufp++;
1879 if (*type != ASN_BIT_STR) {
1880 _asn_type_err(errpre, *type);
1881 return NULL;
1882 }
1883
1884 bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1885 if (NULL == bufp) {
1886 _asn_short_err(errpre, *datalength - 1, asn_length);
1887 return NULL;
1888 }
1889
1890 if ((size_t) asn_length > *strlength) {
1891 _asn_length_err(errpre, (size_t) asn_length, *strlength);
1892 return NULL;
1893 }
1894 if (_asn_bitstring_check(errpre, asn_length, *bufp))
1895 return NULL;
1896
1897 DEBUGDUMPSETUP("recv", data, bufp - data);
1898 DEBUGMSG(("dumpv_recv", " Bitstring: "));
1899 DEBUGMSGHEX(("dumpv_recv", data, asn_length));
1900 DEBUGMSG(("dumpv_recv", "\n"));
1901
1902 memmove(str, bufp, asn_length);
1903 *strlength = (int) asn_length;
1904 *datalength -= (int) asn_length + (bufp - data);
1905 return bufp + asn_length;
1906 }
1907
1908
1909 /**
1910 * @internal
1911 * asn_build_bitstring - Builds an ASN bit string object containing the
1912 * input string.
1913 *
1914 * On entry, datalength is input as the number of valid bytes following
1915 * "data". On exit, it is returned as the number of valid bytes
1916 * following the beginning of the next object.
1917 *
1918 * Returns a pointer to the first byte past the end
1919 * of this object (i.e. the start of the next object).
1920 * Returns NULL on any error.
1921 *
1922 * @param data IN - pointer to start of object
1923 * @param datalength IN/OUT - number of valid bytes left in buffer
1924 * @param type IN - asn type of object
1925 * @param string IN - pointer to start of input buffer
1926 * @param strlength IN - size of input buffer
1927 * @return Returns a pointer to the first byte past the end
1928 * of this object (i.e. the start of the next object).
1929 * Returns NULL on any error.
1930 */
1931 u_char *
asn_build_bitstring(u_char * data,size_t * datalength,u_char type,const u_char * str,size_t strlength)1932 asn_build_bitstring(u_char * data,
1933 size_t * datalength,
1934 u_char type, const u_char * str, size_t strlength)
1935 {
1936 /*
1937 * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
1938 */
1939 static const char *errpre = "build bitstring";
1940 if (_asn_bitstring_check
1941 (errpre, strlength, (u_char)((str) ? *str : 0)))
1942 return NULL;
1943
1944 data = asn_build_header(data, datalength, type, strlength);
1945 if (_asn_build_header_check(errpre, data, *datalength, strlength))
1946 return NULL;
1947
1948 if (strlength > 0 && str)
1949 memmove(data, str, strlength);
1950 else if (strlength > 0 && !str) {
1951 ERROR_MSG("no string passed into asn_build_bitstring\n");
1952 return NULL;
1953 }
1954
1955 *datalength -= strlength;
1956 DEBUGDUMPSETUP("send", data, strlength);
1957 DEBUGMSG(("dumpv_send", " Bitstring: "));
1958 DEBUGMSGHEX(("dumpv_send", data, strlength));
1959 DEBUGMSG(("dumpv_send", "\n"));
1960 return data + strlength;
1961 }
1962
1963 /**
1964 * @internal
1965 * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
1966 * type.
1967 *
1968 * On entry, datalength is input as the number of valid bytes following
1969 * "data". On exit, it is returned as the number of valid bytes
1970 * following the end of this object.
1971 *
1972 * Returns a pointer to the first byte past the end
1973 * of this object (i.e. the start of the next object).
1974 * Returns NULL on any error.
1975 *
1976 * @param data IN - pointer to start of object
1977 * @param datalength IN/OUT - number of valid bytes left in buffer
1978 * @param type OUT - asn type of object
1979 * @param cp IN/OUT - pointer to counter struct
1980 * @param countersize IN - size of output buffer
1981 * @return Returns a pointer to the first byte past the end
1982 * of this object (i.e. the start of the next object).
1983 * Returns NULL on any error.
1984 */
1985 u_char *
asn_parse_unsigned_int64(u_char * data,size_t * datalength,u_char * type,struct counter64 * cp,size_t countersize)1986 asn_parse_unsigned_int64(u_char * data,
1987 size_t * datalength,
1988 u_char * type,
1989 struct counter64 *cp, size_t countersize)
1990 {
1991 /*
1992 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1993 */
1994 static const char *errpre = "parse uint64";
1995 const int uint64sizelimit = (4 * 2) + 1;
1996 register u_char *bufp = data;
1997 u_long asn_length;
1998 register u_long low = 0, high = 0;
1999
2000 if (countersize != sizeof(struct counter64)) {
2001 _asn_size_err(errpre, countersize, sizeof(struct counter64));
2002 return NULL;
2003 }
2004
2005 if (NULL == data || NULL == datalength || NULL == type || NULL == cp) {
2006 ERROR_MSG("parse uint64: NULL pointer");
2007 return NULL;
2008 }
2009
2010 /** need at least 2 bytes to work with: type, length (which might be 0) */
2011 if (*datalength < 2) {
2012 _asn_short_err(errpre, *datalength, 2);
2013 return NULL;
2014 }
2015
2016 *type = *bufp++;
2017 if (*type != ASN_COUNTER64
2018 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2019 && *type != ASN_OPAQUE
2020 #endif
2021 ) {
2022 _asn_type_err(errpre, *type);
2023 return NULL;
2024 }
2025 bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2026 if (NULL == bufp) {
2027 _asn_short_err(errpre, *datalength - 1, asn_length);
2028 return NULL;
2029 }
2030
2031 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2032 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2033 /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_<type> */
2034 if ((*type == ASN_OPAQUE) && (asn_length < 2)) {
2035 _asn_short_err(errpre, asn_length, 2);
2036 return NULL;
2037 }
2038
2039 /*
2040 * 64 bit counters as opaque
2041 */
2042 if ((*type == ASN_OPAQUE) &&
2043 (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
2044 (*bufp == ASN_OPAQUE_TAG1) &&
2045 ((*(bufp + 1) == ASN_OPAQUE_COUNTER64) ||
2046 (*(bufp + 1) == ASN_OPAQUE_U64))) {
2047 /*
2048 * change type to Counter64 or U64
2049 */
2050 *type = *(bufp + 1);
2051 /*
2052 * value is encoded as special format
2053 */
2054 *datalength = asn_length;
2055 bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2056 if (NULL == bufp) {
2057 _asn_short_err("parse opaque uint64", *datalength - 2, asn_length);
2058 return NULL;
2059 }
2060 }
2061 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2062 if (((int) asn_length > uint64sizelimit) ||
2063 (((int) asn_length == uint64sizelimit) && *bufp != 0x00)) {
2064 _asn_length_err(errpre, (size_t) asn_length, uint64sizelimit);
2065 return NULL;
2066 }
2067 *datalength -= (int) asn_length + (bufp - data);
2068 while (asn_length--) {
2069 high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
2070 low = ((low & 0x00FFFFFF) << 8) | *bufp++;
2071 }
2072
2073 CHECK_OVERFLOW_U(high,6);
2074 CHECK_OVERFLOW_U(low,6);
2075
2076 cp->low = low;
2077 cp->high = high;
2078
2079 DEBUGIF("dumpv_recv") {
2080 char i64buf[I64CHARSZ + 1];
2081 printU64(i64buf, cp);
2082 DEBUGMSG(("dumpv_recv", "Counter64: %s\n", i64buf));
2083 }
2084
2085 return bufp;
2086 }
2087
2088
2089 /**
2090 * @internal
2091 * asn_build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
2092 *
2093 * On entry, datalength is input as the number of valid bytes following
2094 * "data". On exit, it is returned as the number of valid bytes
2095 * following the end of this object.
2096 *
2097 * Returns a pointer to the first byte past the end
2098 * of this object (i.e. the start of the next object).
2099 * Returns NULL on any error.
2100 *
2101 * @param data IN - pointer to start of output buffer
2102 * @param datalength IN/OUT - number of valid bytes left in buffer
2103 * @param type IN - asn type of object
2104 * @param cp IN - pointer to counter struct
2105 * @param countersize IN - size of input buffer
2106 * @return Returns a pointer to the first byte past the end
2107 * of this object (i.e. the start of the next object).
2108 * Returns NULL on any error.
2109 */
2110 u_char *
asn_build_unsigned_int64(u_char * data,size_t * datalength,u_char type,const struct counter64 * cp,size_t countersize)2111 asn_build_unsigned_int64(u_char * data,
2112 size_t * datalength,
2113 u_char type,
2114 const struct counter64 *cp, size_t countersize)
2115 {
2116 /*
2117 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
2118 */
2119
2120 register u_long low, high;
2121 register u_long mask, mask2;
2122 int add_null_byte = 0;
2123 size_t intsize;
2124 u_char *initdatap = data;
2125
2126 if (countersize != sizeof(struct counter64)) {
2127 _asn_size_err("build uint64", countersize,
2128 sizeof(struct counter64));
2129 return NULL;
2130 }
2131 intsize = 8;
2132 low = cp->low;
2133 high = cp->high;
2134
2135 CHECK_OVERFLOW_U(high,7);
2136 CHECK_OVERFLOW_U(low,7);
2137
2138 mask = 0xff000000U;
2139 if (high & 0x80000000U) {
2140 /*
2141 * if MSB is set
2142 */
2143 add_null_byte = 1;
2144 intsize++;
2145 } else {
2146 /*
2147 * Truncate "unnecessary" bytes off of the most significant end of this 2's
2148 * complement integer.
2149 * There should be no sequence of 9 consecutive 1's or 0's at the most
2150 * significant end of the integer.
2151 */
2152 mask2 = 0xff800000U;
2153 while ((((high & mask2) == 0) || ((high & mask2) == mask2))
2154 && intsize > 1) {
2155 intsize--;
2156 high = ((high & 0x00ffffffu) << 8) | ((low & mask) >> 24);
2157 low = (low & 0x00ffffffu) << 8;
2158 }
2159 }
2160 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2161 /*
2162 * encode a Counter64 as an opaque (it also works in SNMPv1)
2163 */
2164 /*
2165 * turn into Opaque holding special tagged value
2166 */
2167 if (type == ASN_OPAQUE_COUNTER64) {
2168 /*
2169 * put the tag and length for the Opaque wrapper
2170 */
2171 data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2172 if (_asn_build_header_check
2173 ("build counter u64", data, *datalength, intsize + 3))
2174 return NULL;
2175
2176 /*
2177 * put the special tag and length
2178 */
2179 *data++ = ASN_OPAQUE_TAG1;
2180 *data++ = ASN_OPAQUE_COUNTER64;
2181 *data++ = (u_char) intsize;
2182 *datalength = *datalength - 3;
2183 } else
2184 /*
2185 * Encode the Unsigned int64 in an opaque
2186 */
2187 /*
2188 * turn into Opaque holding special tagged value
2189 */
2190 if (type == ASN_OPAQUE_U64) {
2191 /*
2192 * put the tag and length for the Opaque wrapper
2193 */
2194 data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2195 if (_asn_build_header_check
2196 ("build opaque u64", data, *datalength, intsize + 3))
2197 return NULL;
2198
2199 /*
2200 * put the special tag and length
2201 */
2202 *data++ = ASN_OPAQUE_TAG1;
2203 *data++ = ASN_OPAQUE_U64;
2204 *data++ = (u_char) intsize;
2205 *datalength = *datalength - 3;
2206 } else {
2207 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2208 data = asn_build_header(data, datalength, type, intsize);
2209 if (_asn_build_header_check
2210 ("build uint64", data, *datalength, intsize))
2211 return NULL;
2212
2213 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2214 }
2215 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2216 *datalength -= intsize;
2217 if (add_null_byte == 1) {
2218 *data++ = '\0';
2219 intsize--;
2220 }
2221 while (intsize--) {
2222 *data++ = (u_char) (high >> 24);
2223 high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
2224 low = (low & 0x00ffffff) << 8;
2225
2226 }
2227 DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2228 DEBUGIF("dumpv_send") {
2229 char i64buf[I64CHARSZ + 1];
2230 printU64(i64buf, cp);
2231 DEBUGMSG(("dumpv_send", "%s", i64buf));
2232 }
2233 return data;
2234 }
2235
2236 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2237
2238
2239 /**
2240 * @internal
2241 * asn_parse_signed_int64 - pulls a 64 bit signed long out of an ASN int
2242 * type.
2243 *
2244 * On entry, datalength is input as the number of valid bytes following
2245 * "data". On exit, it is returned as the number of valid bytes
2246 * following the end of this object.
2247 *
2248 * Returns a pointer to the first byte past the end
2249 * of this object (i.e. the start of the next object).
2250 * Returns NULL on any error.
2251
2252 * @param data IN - pointer to start of object
2253 * @param datalength IN/OUT - number of valid bytes left in buffer
2254 * @param type OUT - asn type of object
2255 * @param cp IN/OUT - pointer to counter struct
2256 * @param countersize IN - size of output buffer
2257 * @return Returns a pointer to the first byte past the end
2258 * of this object (i.e. the start of the next object).
2259 * Returns NULL on any error.
2260 */
2261
2262 u_char *
asn_parse_signed_int64(u_char * data,size_t * datalength,u_char * type,struct counter64 * cp,size_t countersize)2263 asn_parse_signed_int64(u_char * data,
2264 size_t * datalength,
2265 u_char * type,
2266 struct counter64 *cp, size_t countersize)
2267 {
2268 static const char *errpre = "parse int64";
2269 const int int64sizelimit = (4 * 2) + 1;
2270 char ebuf[128];
2271 register u_char *bufp = data;
2272 u_long asn_length;
2273 register u_int low = 0, high = 0;
2274
2275 if (countersize != sizeof(struct counter64)) {
2276 _asn_size_err(errpre, countersize, sizeof(struct counter64));
2277 return NULL;
2278 }
2279
2280 if (NULL == data || NULL == datalength || NULL == type || NULL == cp) {
2281 ERROR_MSG("parse int64: NULL pointer");
2282 return NULL;
2283 }
2284
2285 /** need at least 2 bytes to work with: type, length (which might be 0) */
2286 if (*datalength < 2) {
2287 _asn_short_err(errpre, *datalength, 2);
2288 return NULL;
2289 }
2290
2291 *type = *bufp++;
2292 bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2293 if (NULL == bufp) {
2294 _asn_short_err(errpre, *datalength - 1, asn_length);
2295 return NULL;
2296 }
2297
2298 /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_I64 */
2299 if (asn_length < 2) {
2300 _asn_short_err(errpre, asn_length, 2);
2301 return NULL;
2302 }
2303
2304 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2305 if ((*type == ASN_OPAQUE) &&
2306 (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
2307 (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_I64)) {
2308 /*
2309 * change type to Int64
2310 */
2311 *type = *(bufp + 1);
2312 /*
2313 * value is encoded as special format
2314 */
2315 *datalength = asn_length;
2316 bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2317 if (NULL == bufp) {
2318 _asn_short_err("parse opaque int64", *datalength - 2, asn_length);
2319 return NULL;
2320 }
2321 }
2322 /*
2323 * this should always have been true until snmp gets int64 PDU types
2324 */
2325 else {
2326 snprintf(ebuf, sizeof(ebuf),
2327 "%s: wrong type: %d, len %d, buf bytes (%02X,%02X)",
2328 errpre, *type, (int) asn_length, *bufp, *(bufp + 1));
2329 ebuf[ sizeof(ebuf)-1 ] = 0;
2330 ERROR_MSG(ebuf);
2331 return NULL;
2332 }
2333 if (((int) asn_length > int64sizelimit) ||
2334 (((int) asn_length == int64sizelimit) && *bufp != 0x00)) {
2335 _asn_length_err(errpre, (size_t) asn_length, int64sizelimit);
2336 return NULL;
2337 }
2338 *datalength -= (int) asn_length + (bufp - data);
2339 if ((asn_length > 0) && (*bufp & 0x80)) {
2340 low = 0xFFFFFFFFU; /* first byte bit 1 means start the data with 1s */
2341 high = 0xFFFFFF;
2342 }
2343
2344 while (asn_length--) {
2345 high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
2346 low = ((low & 0x00FFFFFF) << 8) | *bufp++;
2347 }
2348
2349 CHECK_OVERFLOW_U(high,8);
2350 CHECK_OVERFLOW_U(low,8);
2351
2352 cp->low = low;
2353 cp->high = high;
2354
2355 DEBUGIF("dumpv_recv") {
2356 char i64buf[I64CHARSZ + 1];
2357 printI64(i64buf, cp);
2358 DEBUGMSG(("dumpv_recv", "Integer64: %s\n", i64buf));
2359 }
2360
2361 return bufp;
2362 }
2363
2364
2365
2366 /**
2367 * @internal
2368 * asn_build_signed_int64 - builds an ASN object containing a 64 bit integer.
2369 *
2370 * On entry, datalength is input as the number of valid bytes following
2371 * "data". On exit, it is returned as the number of valid bytes
2372 * following the end of this object.
2373 *
2374 * Returns a pointer to the first byte past the end
2375 * of this object (i.e. the start of the next object).
2376 * Returns NULL on any error.
2377 *
2378 * @param data IN - pointer to start of output buffer
2379 * @param datalength IN/OUT - number of valid bytes left in buffer
2380 * @param type IN - asn type of object
2381 * @param cp IN - pointer to counter struct
2382 * @param countersize IN - size of input buffer
2383 * @return Returns a pointer to the first byte past the end
2384 * of this object (i.e. the start of the next object).
2385 * Returns NULL on any error.
2386 */
2387 u_char *
asn_build_signed_int64(u_char * data,size_t * datalength,u_char type,const struct counter64 * cp,size_t countersize)2388 asn_build_signed_int64(u_char * data,
2389 size_t * datalength,
2390 u_char type,
2391 const struct counter64 *cp, size_t countersize)
2392 {
2393 /*
2394 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
2395 */
2396
2397 register u_int mask, mask2;
2398 u_long low;
2399 long high; /* MUST be signed because of CHECK_OVERFLOW_S(). */
2400 size_t intsize;
2401 u_char *initdatap = data;
2402
2403 if (countersize != sizeof(struct counter64)) {
2404 _asn_size_err("build int64", countersize,
2405 sizeof(struct counter64));
2406 return NULL;
2407 }
2408 intsize = 8;
2409 low = cp->low;
2410 high = cp->high; /* unsigned to signed conversion */
2411
2412 CHECK_OVERFLOW_S(high,9);
2413 CHECK_OVERFLOW_U(low,9);
2414
2415 /*
2416 * Truncate "unnecessary" bytes off of the most significant end of this
2417 * 2's complement integer. There should be no sequence of 9
2418 * consecutive 1's or 0's at the most significant end of the
2419 * integer.
2420 */
2421 mask = 0xFF000000U;
2422 mask2 = 0xFF800000U;
2423 while ((((high & mask2) == 0) || ((high & mask2) == mask2))
2424 && intsize > 1) {
2425 intsize--;
2426 high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
2427 low = (low & 0x00ffffff) << 8;
2428 }
2429 /*
2430 * until a real int64 gets incorperated into SNMP, we are going to
2431 * encode it as an opaque instead. First, we build the opaque
2432 * header and then the int64 tag type we use to mark it as an
2433 * int64 in the opaque string.
2434 */
2435 data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2436 if (_asn_build_header_check
2437 ("build int64", data, *datalength, intsize + 3))
2438 return NULL;
2439
2440 *data++ = ASN_OPAQUE_TAG1;
2441 *data++ = ASN_OPAQUE_I64;
2442 *data++ = (u_char) intsize;
2443 *datalength -= (3 + intsize);
2444
2445 while (intsize--) {
2446 *data++ = (u_char) (high >> 24);
2447 high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
2448 low = (low & 0x00ffffff) << 8;
2449 }
2450 DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2451 DEBUGIF("dumpv_send") {
2452 char i64buf[I64CHARSZ + 1];
2453 printU64(i64buf, cp);
2454 DEBUGMSG(("dumpv_send", "%s\n", i64buf));
2455 }
2456 return data;
2457 }
2458
2459
2460 /**
2461 * @internal
2462 * asn_parse_float - pulls a single precision floating-point out of an opaque type.
2463 *
2464 * On entry, datalength is input as the number of valid bytes following
2465 * "data". On exit, it is returned as the number of valid bytes
2466 * following the end of this object.
2467 *
2468 * Returns a pointer to the first byte past the end
2469 * of this object (i.e. the start of the next object).
2470 * Returns NULL on any error.
2471 *
2472 * @param data IN - pointer to start of object
2473 * @param datalength IN/OUT - number of valid bytes left in buffer
2474 * @param type OUT - asn type of object
2475 * @param floatp IN/OUT - pointer to float
2476 * @param floatsize IN - size of output buffer
2477 * @return Returns a pointer to the first byte past the end
2478 * of this object (i.e. the start of the next object).
2479 * Returns NULL on any error.
2480 */
2481 u_char *
asn_parse_float(u_char * data,size_t * datalength,u_char * type,float * floatp,size_t floatsize)2482 asn_parse_float(u_char * data,
2483 size_t * datalength,
2484 u_char * type, float *floatp, size_t floatsize)
2485 {
2486 static const char *errpre = "parse float";
2487 register u_char *bufp = data;
2488 u_long asn_length;
2489 union {
2490 float floatVal;
2491 long longVal;
2492 u_char c[sizeof(float)];
2493 } fu;
2494
2495 if (floatsize != sizeof(float)) {
2496 _asn_size_err("parse float", floatsize, sizeof(float));
2497 return NULL;
2498 }
2499
2500 if (NULL == data || NULL == datalength || NULL == type || NULL == floatp) {
2501 ERROR_MSG("parse float: NULL pointer");
2502 return NULL;
2503 }
2504
2505 /** need at least 2 bytes to work with: type, length (which might be 0) */
2506 if (*datalength < 2) {
2507 _asn_short_err(errpre, *datalength, 2);
2508 return NULL;
2509 }
2510
2511 *type = *bufp++;
2512 bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2513 if (NULL == bufp) {
2514 _asn_short_err(errpre, *datalength - 1, asn_length);
2515 return NULL;
2516 }
2517
2518 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2519 /*
2520 * the float is encoded as an opaque
2521 */
2522 if ((*type == ASN_OPAQUE) &&
2523 (asn_length == ASN_OPAQUE_FLOAT_BER_LEN) &&
2524 (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_FLOAT)) {
2525
2526 /*
2527 * value is encoded as special format
2528 */
2529 *datalength = asn_length;
2530 bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2531 if (NULL == bufp) {
2532 _asn_short_err("parse opaque float", *datalength - 2, asn_length);
2533 return NULL;
2534 }
2535 /*
2536 * change type to Float
2537 */
2538 *type = ASN_OPAQUE_FLOAT;
2539 }
2540
2541 if (*type != ASN_OPAQUE_FLOAT) {
2542 _asn_type_err(errpre, *type);
2543 return NULL;
2544 }
2545
2546 if (asn_length != sizeof(float)) {
2547 _asn_size_err("parse seq float", asn_length, sizeof(float));
2548 return NULL;
2549 }
2550
2551 *datalength -= (int) asn_length + (bufp - data);
2552 memcpy(&fu.c[0], bufp, asn_length);
2553
2554 /*
2555 * correct for endian differences
2556 */
2557 fu.longVal = ntohl(fu.longVal);
2558
2559 *floatp = fu.floatVal;
2560
2561 DEBUGMSG(("dumpv_recv", "Opaque float: %f\n", *floatp));
2562 return bufp;
2563 }
2564
2565 /**
2566 * @internal
2567 * asn_build_float - builds an ASN object containing a single precision floating-point
2568 * number in an Opaque value.
2569 *
2570 * On entry, datalength is input as the number of valid bytes following
2571 * "data". On exit, it is returned as the number of valid bytes
2572 * following the end of this object.
2573 *
2574 * Returns a pointer to the first byte past the end
2575 * of this object (i.e. the start of the next object).
2576 * Returns NULL on any error.
2577 *
2578 * @param data IN - pointer to start of object
2579 * @param datalength IN/OUT - number of valid bytes left in buffer
2580 * @param type IN - asn type of object
2581 * @param floatp IN - pointer to float
2582 * @param floatsize IN - size of input buffer
2583 * @return Returns a pointer to the first byte past the end
2584 * of this object (i.e. the start of the next object).
2585 * Returns NULL on any error.
2586
2587 */
2588 u_char *
asn_build_float(u_char * data,size_t * datalength,u_char type,const float * floatp,size_t floatsize)2589 asn_build_float(u_char * data,
2590 size_t * datalength,
2591 u_char type, const float *floatp, size_t floatsize)
2592 {
2593 union {
2594 float floatVal;
2595 int intVal;
2596 u_char c[sizeof(float)];
2597 } fu;
2598 u_char *initdatap = data;
2599
2600 if (floatsize != sizeof(float)) {
2601 _asn_size_err("build float", floatsize, sizeof(float));
2602 return NULL;
2603 }
2604 /*
2605 * encode the float as an opaque
2606 */
2607 /*
2608 * turn into Opaque holding special tagged value
2609 */
2610
2611 /*
2612 * put the tag and length for the Opaque wrapper
2613 */
2614 data = asn_build_header(data, datalength, ASN_OPAQUE, floatsize + 3);
2615 if (_asn_build_header_check
2616 ("build float", data, *datalength, (floatsize + 3)))
2617 return NULL;
2618
2619 /*
2620 * put the special tag and length
2621 */
2622 *data++ = ASN_OPAQUE_TAG1;
2623 *data++ = ASN_OPAQUE_FLOAT;
2624 *data++ = (u_char) floatsize;
2625 *datalength = *datalength - 3;
2626
2627 fu.floatVal = *floatp;
2628 /*
2629 * correct for endian differences
2630 */
2631 fu.intVal = htonl(fu.intVal);
2632
2633 *datalength -= floatsize;
2634 memcpy(data, &fu.c[0], floatsize);
2635
2636 DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2637 DEBUGMSG(("dumpv_send", "Opaque float: %f\n", *floatp));
2638 data += floatsize;
2639 return data;
2640 }
2641
2642
2643 /**
2644 * @internal
2645 * asn_parse_double - pulls a double out of an opaque type.
2646 *
2647 * On entry, datalength is input as the number of valid bytes following
2648 * "data". On exit, it is returned as the number of valid bytes
2649 * following the end of this object.
2650 *
2651 * Returns a pointer to the first byte past the end
2652 * of this object (i.e. the start of the next object).
2653 * Returns NULL on any error.
2654 *
2655 * @param data IN - pointer to start of object
2656 * @param datalength IN/OUT - number of valid bytes left in buffer
2657 * @param type OUT - asn type of object
2658 * @param doublep IN/OUT - pointer to double
2659 * @param doublesize IN - size of output buffer
2660 * @return Returns a pointer to the first byte past the end
2661 * of this object (i.e. the start of the next object).
2662 * Returns NULL on any error.
2663 */
2664 u_char *
asn_parse_double(u_char * data,size_t * datalength,u_char * type,double * doublep,size_t doublesize)2665 asn_parse_double(u_char * data,
2666 size_t * datalength,
2667 u_char * type, double *doublep, size_t doublesize)
2668 {
2669 static const char *errpre = "parse double";
2670 register u_char *bufp = data;
2671 u_long asn_length;
2672 long tmp;
2673 union {
2674 double doubleVal;
2675 int intVal[2];
2676 u_char c[sizeof(double)];
2677 } fu;
2678
2679
2680 if (doublesize != sizeof(double)) {
2681 _asn_size_err("parse double", doublesize, sizeof(double));
2682 return NULL;
2683 }
2684
2685 if (NULL == data || NULL == datalength || NULL == type || NULL == doublep) {
2686 ERROR_MSG("parse double: NULL pointer");
2687 return NULL;
2688 }
2689
2690 /** need at least 2 bytes to work with: type, length (which might be 0) */
2691 if (*datalength < 2) {
2692 _asn_short_err(errpre, *datalength, 2);
2693 return NULL;
2694 }
2695
2696 *type = *bufp++;
2697 bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2698 if (NULL == bufp) {
2699 _asn_short_err(errpre, *datalength - 1, asn_length);
2700 return NULL;
2701 }
2702
2703 DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2704 /*
2705 * the double is encoded as an opaque
2706 */
2707 /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_DOUBLE */
2708 if ((*type == ASN_OPAQUE) && (asn_length < 2)) {
2709 _asn_short_err(errpre, asn_length, 2);
2710 return NULL;
2711 }
2712 if ((*type == ASN_OPAQUE) &&
2713 (asn_length == ASN_OPAQUE_DOUBLE_BER_LEN) &&
2714 (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_DOUBLE)) {
2715
2716 /*
2717 * value is encoded as special format
2718 */
2719 *datalength = asn_length;
2720 bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2721 if (NULL == bufp) {
2722 _asn_short_err("parse opaque double", *datalength - 2, asn_length);
2723 return NULL;
2724 }
2725
2726 /*
2727 * change type to Double
2728 */
2729 *type = ASN_OPAQUE_DOUBLE;
2730 }
2731
2732 if (*type != ASN_OPAQUE_DOUBLE) {
2733 _asn_type_err(errpre, *type);
2734 return NULL;
2735 }
2736
2737 if (asn_length != sizeof(double)) {
2738 _asn_size_err("parse seq double", asn_length, sizeof(double));
2739 return NULL;
2740 }
2741 *datalength -= (int) asn_length + (bufp - data);
2742 memcpy(&fu.c[0], bufp, asn_length);
2743
2744 /*
2745 * correct for endian differences
2746 */
2747
2748 tmp = ntohl(fu.intVal[0]);
2749 fu.intVal[0] = ntohl(fu.intVal[1]);
2750 fu.intVal[1] = tmp;
2751
2752 *doublep = fu.doubleVal;
2753 DEBUGMSG(("dumpv_recv", " Opaque Double:\t%f\n", *doublep));
2754
2755 return bufp;
2756 }
2757
2758
2759 /**
2760 * @internal
2761 * asn_build_double - builds an ASN object containing a double
2762 * number in an Opaque value.
2763 *
2764 * On entry, datalength is input as the number of valid bytes following
2765 * "data". On exit, it is returned as the number of valid bytes
2766 * following the end of this object.
2767 *
2768 * Returns a pointer to the first byte past the end
2769 * of this object (i.e. the start of the next object).
2770 * Returns NULL on any error.
2771 *
2772 * @param data IN - pointer to start of object
2773 * @param datalength IN/OUT - number of valid bytes left in buffer
2774 * @param type IN - asn type of object
2775 * @param doublep IN - pointer to double
2776 * @param doublesize IN - size of input buffer
2777 * @return Returns a pointer to the first byte past the end
2778 * of this object (i.e. the start of the next object).
2779 * Returns NULL on any error.
2780 */
2781 u_char *
asn_build_double(u_char * data,size_t * datalength,u_char type,const double * doublep,size_t doublesize)2782 asn_build_double(u_char * data,
2783 size_t * datalength,
2784 u_char type, const double *doublep, size_t doublesize)
2785 {
2786 long tmp;
2787 union {
2788 double doubleVal;
2789 int intVal[2];
2790 u_char c[sizeof(double)];
2791 } fu;
2792 u_char *initdatap = data;
2793
2794 if (doublesize != sizeof(double)) {
2795 _asn_size_err("build double", doublesize, sizeof(double));
2796 return NULL;
2797 }
2798
2799 /*
2800 * encode the double as an opaque
2801 */
2802 /*
2803 * turn into Opaque holding special tagged value
2804 */
2805
2806 /*
2807 * put the tag and length for the Opaque wrapper
2808 */
2809 data = asn_build_header(data, datalength, ASN_OPAQUE, doublesize + 3);
2810 if (_asn_build_header_check
2811 ("build double", data, *datalength, doublesize + 3))
2812 return NULL;
2813
2814 /*
2815 * put the special tag and length
2816 */
2817 *data++ = ASN_OPAQUE_TAG1;
2818 *data++ = ASN_OPAQUE_DOUBLE;
2819 *data++ = (u_char) doublesize;
2820 *datalength = *datalength - 3;
2821
2822 fu.doubleVal = *doublep;
2823 /*
2824 * correct for endian differences
2825 */
2826 tmp = htonl(fu.intVal[0]);
2827 fu.intVal[0] = htonl(fu.intVal[1]);
2828 fu.intVal[1] = tmp;
2829 *datalength -= doublesize;
2830 memcpy(data, &fu.c[0], doublesize);
2831
2832 data += doublesize;
2833 DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2834 DEBUGMSG(("dumpv_send", " Opaque double: %f\n", *doublep));
2835 return data;
2836 }
2837
2838 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2839
2840
2841 /**
2842 * @internal
2843 * This function increases the size of the buffer pointed to by *pkt, which
2844 * is initially of size *pkt_len. Contents are preserved **AT THE TOP END OF
2845 * THE BUFFER** (hence making this function useful for reverse encoding).
2846 * You can change the reallocation scheme, but you **MUST** guarantee to
2847 * allocate **AT LEAST** one extra byte. If memory cannot be reallocated,
2848 * then return 0; otherwise return 1.
2849 *
2850 * @param pkt buffer to increase
2851 * @param pkt_len initial buffer size
2852 *
2853 * @return 1 on success 0 on error (memory cannot be reallocated)
2854 */
2855 int
asn_realloc(u_char ** pkt,size_t * pkt_len)2856 asn_realloc(u_char ** pkt, size_t * pkt_len)
2857 {
2858 if (pkt != NULL && pkt_len != NULL) {
2859 size_t old_pkt_len = *pkt_len;
2860
2861 DEBUGMSGTL(("asn_realloc", " old_pkt %8p, old_pkt_len %lu\n",
2862 *pkt, (unsigned long)old_pkt_len));
2863
2864 if (snmp_realloc(pkt, pkt_len)) {
2865 DEBUGMSGTL(("asn_realloc", " new_pkt %8p, new_pkt_len %lu\n",
2866 *pkt, (unsigned long)*pkt_len));
2867 DEBUGMSGTL(("asn_realloc",
2868 " memmove(%8p + %08x, %8p, %08x)\n",
2869 *pkt, (unsigned)(*pkt_len - old_pkt_len),
2870 *pkt, (unsigned)old_pkt_len));
2871 memmove(*pkt + (*pkt_len - old_pkt_len), *pkt, old_pkt_len);
2872 memset(*pkt, (int) ' ', *pkt_len - old_pkt_len);
2873 return 1;
2874 } else {
2875 DEBUGMSG(("asn_realloc", " CANNOT REALLOC()\n"));
2876 }
2877 }
2878 return 0;
2879 }
2880
2881 #ifdef NETSNMP_USE_REVERSE_ASNENCODING
2882
2883 /**
2884 * @internal
2885 * reverse builds an ASN header for a length with
2886 * length specified.
2887 *
2888 * @param pkt IN/OUT address of the begining of the buffer.
2889 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
2890 * @param offset IN/OUT offset to the start of the buffer where to write
2891 * @param r IN if not zero reallocate the buffer to fit the
2892 * needed size.
2893 * @param length IN - length of object
2894 *
2895 * @return 1 on success, 0 on error
2896 */
2897 int
asn_realloc_rbuild_length(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,size_t length)2898 asn_realloc_rbuild_length(u_char ** pkt, size_t * pkt_len,
2899 size_t * offset, int r, size_t length)
2900 {
2901 static const char *errpre = "build length";
2902 char ebuf[128];
2903 int tmp_int;
2904 size_t start_offset = *offset;
2905
2906 if (length <= 0x7f) {
2907 if (((*pkt_len - *offset) < 1)
2908 && !(r && asn_realloc(pkt, pkt_len))) {
2909 snprintf(ebuf, sizeof(ebuf),
2910 "%s: bad length < 1 :%ld, %lu", errpre,
2911 (long)(*pkt_len - *offset), (unsigned long)length);
2912 ebuf[ sizeof(ebuf)-1 ] = 0;
2913 ERROR_MSG(ebuf);
2914 return 0;
2915 }
2916 *(*pkt + *pkt_len - (++*offset)) = length;
2917 } else {
2918 while (length > 0xff) {
2919 if (((*pkt_len - *offset) < 1)
2920 && !(r && asn_realloc(pkt, pkt_len))) {
2921 snprintf(ebuf, sizeof(ebuf),
2922 "%s: bad length < 1 :%ld, %lu", errpre,
2923 (long)(*pkt_len - *offset), (unsigned long)length);
2924 ebuf[ sizeof(ebuf)-1 ] = 0;
2925 ERROR_MSG(ebuf);
2926 return 0;
2927 }
2928 *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
2929 length >>= 8;
2930 }
2931
2932 while ((*pkt_len - *offset) < 2) {
2933 if (!(r && asn_realloc(pkt, pkt_len))) {
2934 snprintf(ebuf, sizeof(ebuf),
2935 "%s: bad length < 1 :%ld, %lu", errpre,
2936 (long)(*pkt_len - *offset), (unsigned long)length);
2937 ebuf[ sizeof(ebuf)-1 ] = 0;
2938 ERROR_MSG(ebuf);
2939 return 0;
2940 }
2941 }
2942
2943 *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
2944 tmp_int = *offset - start_offset;
2945 *(*pkt + *pkt_len - (++*offset)) = tmp_int | 0x80;
2946 }
2947
2948 return 1;
2949 }
2950
2951 /**
2952 * @internal
2953 * builds an ASN header for an object with the ID and
2954 * length specified.
2955 *
2956 * @see asn_build_header
2957 *
2958 * @param pkt IN/OUT address of the begining of the buffer.
2959 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
2960 * @param offset IN/OUT offset to the start of the buffer where to write
2961 * @param r IN if not zero reallocate the buffer to fit the
2962 * needed size.
2963 * @param type IN - type of object
2964 * @param length IN - length of object
2965 *
2966 * @return 1 on success, 0 on error
2967 */
2968 int
asn_realloc_rbuild_header(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,u_char type,size_t length)2969 asn_realloc_rbuild_header(u_char ** pkt, size_t * pkt_len,
2970 size_t * offset, int r,
2971 u_char type, size_t length)
2972 {
2973 char ebuf[128];
2974
2975 if (asn_realloc_rbuild_length(pkt, pkt_len, offset, r, length)) {
2976 if (((*pkt_len - *offset) < 1)
2977 && !(r && asn_realloc(pkt, pkt_len))) {
2978 snprintf(ebuf, sizeof(ebuf),
2979 "bad header length < 1 :%ld, %lu",
2980 (long)(*pkt_len - *offset), (unsigned long)length);
2981 ebuf[ sizeof(ebuf)-1 ] = 0;
2982 ERROR_MSG(ebuf);
2983 return 0;
2984 }
2985 *(*pkt + *pkt_len - (++*offset)) = type;
2986 return 1;
2987 }
2988 return 0;
2989 }
2990
2991 /**
2992 * @internal
2993 * builds an ASN object containing an int.
2994 *
2995 * @see asn_build_int
2996 *
2997 * @param pkt IN/OUT address of the begining of the buffer.
2998 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
2999 * @param offset IN/OUT offset to the start of the buffer where to write
3000 * @param r IN if not zero reallocate the buffer to fit the
3001 * needed size.
3002 * @param type IN - type of object
3003 * @param intp IN - pointer to start of long integer
3004 * @param intsize IN - size of input buffer
3005 *
3006 * @return 1 on success, 0 on error
3007 */
3008 int
asn_realloc_rbuild_int(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,u_char type,const long * intp,size_t intsize)3009 asn_realloc_rbuild_int(u_char ** pkt, size_t * pkt_len,
3010 size_t * offset, int r,
3011 u_char type, const long *intp, size_t intsize)
3012 {
3013 static const char *errpre = "build int";
3014 register long integer = *intp;
3015 int testvalue;
3016 size_t start_offset = *offset;
3017
3018 if (intsize != sizeof(long)) {
3019 _asn_size_err(errpre, intsize, sizeof(long));
3020 return 0;
3021 }
3022
3023 CHECK_OVERFLOW_S(integer,10);
3024 testvalue = (integer < 0) ? -1 : 0;
3025
3026 if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3027 return 0;
3028 }
3029 *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3030 integer >>= 8;
3031
3032 while (integer != testvalue) {
3033 if (((*pkt_len - *offset) < 1)
3034 && !(r && asn_realloc(pkt, pkt_len))) {
3035 return 0;
3036 }
3037 *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3038 integer >>= 8;
3039 }
3040
3041 if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) {
3042 /*
3043 * Make sure left most bit is representational of the rest of the bits
3044 * that aren't encoded.
3045 */
3046 if (((*pkt_len - *offset) < 1)
3047 && !(r && asn_realloc(pkt, pkt_len))) {
3048 return 0;
3049 }
3050 *(*pkt + *pkt_len - (++*offset)) = testvalue & 0xff;
3051 }
3052
3053 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3054 (*offset - start_offset))) {
3055 if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
3056 (*offset - start_offset))) {
3057 return 0;
3058 } else {
3059 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3060 (*offset - start_offset));
3061 DEBUGMSG(("dumpv_send", " Integer:\t%ld (0x%.2lX)\n", *intp,
3062 *intp));
3063 return 1;
3064 }
3065 }
3066
3067 return 0;
3068 }
3069
3070 /**
3071 * @internal
3072 * builds an ASN object containing an string.
3073 *
3074 * @see asn_build_string
3075 *
3076 * @param pkt IN/OUT address of the begining of the buffer.
3077 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3078 * @param offset IN/OUT offset to the start of the buffer where to write
3079 * @param r IN if not zero reallocate the buffer to fit the
3080 * needed size.
3081 * @param type IN - type of object
3082 * @param string IN - pointer to start of the string
3083 * @param strlength IN - size of input buffer
3084 *
3085 * @return 1 on success, 0 on error
3086 */
3087
3088 int
asn_realloc_rbuild_string(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,u_char type,const u_char * str,size_t strlength)3089 asn_realloc_rbuild_string(u_char ** pkt, size_t * pkt_len,
3090 size_t * offset, int r,
3091 u_char type,
3092 const u_char * str, size_t strlength)
3093 {
3094 static const char *errpre = "build string";
3095 size_t start_offset = *offset;
3096
3097 while ((*pkt_len - *offset) < strlength) {
3098 if (!(r && asn_realloc(pkt, pkt_len))) {
3099 return 0;
3100 }
3101 }
3102
3103 *offset += strlength;
3104 memcpy(*pkt + *pkt_len - *offset, str, strlength);
3105
3106 if (asn_realloc_rbuild_header
3107 (pkt, pkt_len, offset, r, type, strlength)) {
3108 if (_asn_realloc_build_header_check
3109 (errpre, pkt, pkt_len, strlength)) {
3110 return 0;
3111 } else {
3112 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3113 *offset - start_offset);
3114 DEBUGIF("dumpv_send") {
3115 if (strlength == 0) {
3116 DEBUGMSG(("dumpv_send", " String: [NULL]\n"));
3117 } else {
3118 u_char *buf = (u_char *) malloc(2 * strlength);
3119 size_t l =
3120 (buf != NULL) ? (2 * strlength) : 0, ol = 0;
3121
3122 if (sprint_realloc_asciistring
3123 (&buf, &l, &ol, 1, str, strlength)) {
3124 DEBUGMSG(("dumpv_send", " String:\t%s\n", buf));
3125 } else {
3126 if (buf == NULL) {
3127 DEBUGMSG(("dumpv_send",
3128 " String:\t[TRUNCATED]\n"));
3129 } else {
3130 DEBUGMSG(("dumpv_send",
3131 " String:\t%s [TRUNCATED]\n", buf));
3132 }
3133 }
3134 if (buf != NULL) {
3135 free(buf);
3136 }
3137 }
3138 }
3139 }
3140 return 1;
3141 }
3142
3143 return 0;
3144 }
3145
3146 /**
3147 * @internal
3148 * builds an ASN object containing an unsigned int.
3149 *
3150 * @see asn_build_unsigned_int
3151 *
3152 * @param pkt IN/OUT address of the begining of the buffer.
3153 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3154 * @param offset IN/OUT offset to the start of the buffer where to write
3155 * @param r IN if not zero reallocate the buffer to fit the
3156 * needed size.
3157 * @param type IN - type of object
3158 * @param intp IN - pointer to start of unsigned int
3159 * @param intsize IN - size of input buffer
3160 *
3161 * @return 1 on success, 0 on error
3162 */
3163 int
asn_realloc_rbuild_unsigned_int(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,u_char type,const u_long * intp,size_t intsize)3164 asn_realloc_rbuild_unsigned_int(u_char ** pkt, size_t * pkt_len,
3165 size_t * offset, int r,
3166 u_char type, const u_long * intp, size_t intsize)
3167 {
3168 static const char *errpre = "build uint";
3169 register u_long integer = *intp;
3170 size_t start_offset = *offset;
3171
3172 if (intsize != sizeof(unsigned long)) {
3173 _asn_size_err(errpre, intsize, sizeof(unsigned long));
3174 return 0;
3175 }
3176
3177 CHECK_OVERFLOW_U(integer,11);
3178
3179 if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3180 return 0;
3181 }
3182 *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3183 integer >>= 8;
3184
3185 while (integer != 0) {
3186 if (((*pkt_len - *offset) < 1)
3187 && !(r && asn_realloc(pkt, pkt_len))) {
3188 return 0;
3189 }
3190 *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3191 integer >>= 8;
3192 }
3193
3194 if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
3195 /*
3196 * Make sure left most bit is representational of the rest of the bits
3197 * that aren't encoded.
3198 */
3199 if (((*pkt_len - *offset) < 1)
3200 && !(r && asn_realloc(pkt, pkt_len))) {
3201 return 0;
3202 }
3203 *(*pkt + *pkt_len - (++*offset)) = 0;
3204 }
3205
3206 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3207 (*offset - start_offset))) {
3208 if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
3209 (*offset - start_offset))) {
3210 return 0;
3211 } else {
3212 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3213 (*offset - start_offset));
3214 DEBUGMSG(("dumpv_send", " UInteger:\t%lu (0x%.2lX)\n", *intp,
3215 *intp));
3216 return 1;
3217 }
3218 }
3219
3220 return 0;
3221 }
3222
3223 /**
3224 * @internal
3225 * builds an ASN object containing an sequence.
3226 *
3227 * @see asn_build_sequence
3228 *
3229 * @param pkt IN/OUT address of the begining of the buffer.
3230 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3231 * @param offset IN/OUT offset to the start of the buffer where to write
3232 * @param r IN if not zero reallocate the buffer to fit the
3233 * needed size.
3234 * @param type IN - type of object
3235 * @param length IN - length of object
3236 *
3237 * @return 1 on success, 0 on error
3238 */
3239
3240 int
asn_realloc_rbuild_sequence(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,u_char type,size_t length)3241 asn_realloc_rbuild_sequence(u_char ** pkt, size_t * pkt_len,
3242 size_t * offset, int r,
3243 u_char type, size_t length)
3244 {
3245 return asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3246 length);
3247 }
3248
3249 /**
3250 * @internal
3251 * builds an ASN object containing an objid.
3252 *
3253 * @see asn_build_objid
3254 *
3255 * @param pkt IN/OUT address of the begining of the buffer.
3256 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3257 * @param offset IN/OUT offset to the start of the buffer where to write
3258 * @param r IN if not zero reallocate the buffer to fit the
3259 * needed size.
3260 * @param type IN - type of object
3261 * @param objid IN - pointer to the object id
3262 * @param objidlength IN - length of the input
3263 *
3264 * @return 1 on success, 0 on error
3265 */
3266
3267 int
asn_realloc_rbuild_objid(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,u_char type,const oid * objid,size_t objidlength)3268 asn_realloc_rbuild_objid(u_char ** pkt, size_t * pkt_len,
3269 size_t * offset, int r,
3270 u_char type,
3271 const oid * objid, size_t objidlength)
3272 {
3273 /*
3274 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
3275 * subidentifier ::= {leadingbyte}* lastbyte
3276 * leadingbyte ::= 1 7bitvalue
3277 * lastbyte ::= 0 7bitvalue
3278 */
3279 register size_t i;
3280 register oid tmpint;
3281 size_t start_offset = *offset;
3282 const char *errpre = "build objid";
3283
3284 /*
3285 * Check if there are at least 2 sub-identifiers.
3286 */
3287 if (objidlength == 0) {
3288 /*
3289 * There are not, so make OID have two with value of zero.
3290 */
3291 while ((*pkt_len - *offset) < 2) {
3292 if (!(r && asn_realloc(pkt, pkt_len))) {
3293 return 0;
3294 }
3295 }
3296
3297 *(*pkt + *pkt_len - (++*offset)) = 0;
3298 *(*pkt + *pkt_len - (++*offset)) = 0;
3299 } else if (objid[0] > 2) {
3300 ERROR_MSG("build objid: bad first subidentifier");
3301 return 0;
3302 } else if (objidlength == 1) {
3303 /*
3304 * Encode the first value.
3305 */
3306 if (((*pkt_len - *offset) < 1)
3307 && !(r && asn_realloc(pkt, pkt_len))) {
3308 return 0;
3309 }
3310 *(*pkt + *pkt_len - (++*offset)) = (u_char) objid[0];
3311 } else {
3312 for (i = objidlength; i > 2; i--) {
3313 tmpint = objid[i - 1];
3314 CHECK_OVERFLOW_U(tmpint,12);
3315
3316 if (((*pkt_len - *offset) < 1)
3317 && !(r && asn_realloc(pkt, pkt_len))) {
3318 return 0;
3319 }
3320 *(*pkt + *pkt_len - (++*offset)) = (u_char) tmpint & 0x7f;
3321 tmpint >>= 7;
3322
3323 while (tmpint > 0) {
3324 if (((*pkt_len - *offset) < 1)
3325 && !(r && asn_realloc(pkt, pkt_len))) {
3326 return 0;
3327 }
3328 *(*pkt + *pkt_len - (++*offset)) =
3329 (u_char) ((tmpint & 0x7f) | 0x80);
3330 tmpint >>= 7;
3331 }
3332 }
3333
3334 /*
3335 * Combine the first two values.
3336 */
3337 if ((objid[1] > 40) &&
3338 (objid[0] < 2)) {
3339 ERROR_MSG("build objid: bad second subidentifier");
3340 return 0;
3341 }
3342 tmpint = ((objid[0] * 40) + objid[1]);
3343 if (((*pkt_len - *offset) < 1)
3344 && !(r && asn_realloc(pkt, pkt_len))) {
3345 return 0;
3346 }
3347 *(*pkt + *pkt_len - (++*offset)) = (u_char) tmpint & 0x7f;
3348 tmpint >>= 7;
3349
3350 while (tmpint > 0) {
3351 if (((*pkt_len - *offset) < 1)
3352 && !(r && asn_realloc(pkt, pkt_len))) {
3353 return 0;
3354 }
3355 *(*pkt + *pkt_len - (++*offset)) =
3356 (u_char) ((tmpint & 0x7f) | 0x80);
3357 tmpint >>= 7;
3358 }
3359 }
3360
3361 tmpint = *offset - start_offset;
3362 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3363 (*offset - start_offset))) {
3364 if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
3365 (*offset - start_offset))) {
3366 return 0;
3367 } else {
3368 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3369 (*offset - start_offset));
3370 DEBUGMSG(("dumpv_send", " ObjID: "));
3371 DEBUGMSGOID(("dumpv_send", objid, objidlength));
3372 DEBUGMSG(("dumpv_send", "\n"));
3373 return 1;
3374 }
3375 }
3376
3377 return 0;
3378 }
3379
3380 /**
3381 * @internal
3382 * builds an ASN object containing an null object.
3383 *
3384 * @see asn_build_null
3385 *
3386 * @param pkt IN/OUT address of the begining of the buffer.
3387 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3388 * @param offset IN/OUT offset to the start of the buffer where to write
3389 * @param r IN if not zero reallocate the buffer to fit the
3390 * needed size.
3391 * @param type IN - type of object
3392 *
3393 * @return 1 on success, 0 on error
3394 */
3395
3396 int
asn_realloc_rbuild_null(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,u_char type)3397 asn_realloc_rbuild_null(u_char ** pkt, size_t * pkt_len,
3398 size_t * offset, int r, u_char type)
3399 {
3400 /*
3401 * ASN.1 null ::= 0x05 0x00
3402 */
3403 size_t start_offset = *offset;
3404
3405 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 0)) {
3406 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3407 (*offset - start_offset));
3408 DEBUGMSG(("dumpv_send", " NULL\n"));
3409 return 1;
3410 } else {
3411 return 0;
3412 }
3413 }
3414
3415 /**
3416 * @internal
3417 * builds an ASN object containing an bitstring.
3418 *
3419 * @see asn_build_bitstring
3420 *
3421 * @param pkt IN/OUT address of the begining of the buffer.
3422 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3423 * @param offset IN/OUT offset to the start of the buffer where to write
3424 * @param r IN if not zero reallocate the buffer to fit the
3425 * needed size.
3426 * @param type IN - type of object
3427 * @param string IN - pointer to the string
3428 * @param strlength IN - length of the input
3429 *
3430 * @return 1 on success, 0 on error
3431 */
3432
3433 int
asn_realloc_rbuild_bitstring(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,u_char type,const u_char * str,size_t strlength)3434 asn_realloc_rbuild_bitstring(u_char ** pkt, size_t * pkt_len,
3435 size_t * offset, int r,
3436 u_char type,
3437 const u_char * str, size_t strlength)
3438 {
3439 /*
3440 * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
3441 */
3442 static const char *errpre = "build bitstring";
3443 size_t start_offset = *offset;
3444
3445 while ((*pkt_len - *offset) < strlength) {
3446 if (!(r && asn_realloc(pkt, pkt_len))) {
3447 return 0;
3448 }
3449 }
3450
3451 *offset += strlength;
3452 memcpy(*pkt + *pkt_len - *offset, str, strlength);
3453
3454 if (asn_realloc_rbuild_header
3455 (pkt, pkt_len, offset, r, type, strlength)) {
3456 if (_asn_realloc_build_header_check
3457 (errpre, pkt, pkt_len, strlength)) {
3458 return 0;
3459 } else {
3460 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3461 *offset - start_offset);
3462 DEBUGIF("dumpv_send") {
3463 if (strlength == 0) {
3464 DEBUGMSG(("dumpv_send", " Bitstring: [NULL]\n"));
3465 } else {
3466 u_char *buf = (u_char *) malloc(2 * strlength);
3467 size_t l =
3468 (buf != NULL) ? (2 * strlength) : 0, ol = 0;
3469
3470 if (sprint_realloc_asciistring
3471 (&buf, &l, &ol, 1, str, strlength)) {
3472 DEBUGMSG(("dumpv_send", " Bitstring:\t%s\n",
3473 buf));
3474 } else {
3475 if (buf == NULL) {
3476 DEBUGMSG(("dumpv_send",
3477 " Bitstring:\t[TRUNCATED]\n"));
3478 } else {
3479 DEBUGMSG(("dumpv_send",
3480 " Bitstring:\t%s [TRUNCATED]\n",
3481 buf));
3482 }
3483 }
3484 if (buf != NULL) {
3485 free(buf);
3486 }
3487 }
3488 }
3489 }
3490 return 1;
3491 }
3492
3493 return 0;
3494 }
3495
3496 /**
3497 * @internal
3498 * builds an ASN object containing an unsigned int64.
3499 *
3500 * @see asn_build_unsigned_int64
3501 *
3502 * @param pkt IN/OUT address of the begining of the buffer.
3503 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3504 * @param offset IN/OUT offset to the start of the buffer where to write
3505 * @param r IN if not zero reallocate the buffer to fit the
3506 * needed size.
3507 * @param type IN - type of object
3508 * @param cp IN - pointer to counter struct
3509 * @param countersize IN - size of input buffer
3510 *
3511 * @return 1 on success, 0 on error
3512 */
3513 int
asn_realloc_rbuild_unsigned_int64(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,u_char type,const struct counter64 * cp,size_t countersize)3514 asn_realloc_rbuild_unsigned_int64(u_char ** pkt, size_t * pkt_len,
3515 size_t * offset, int r,
3516 u_char type,
3517 const struct counter64 *cp, size_t countersize)
3518 {
3519 /*
3520 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
3521 */
3522 register u_long low = cp->low, high = cp->high;
3523 size_t intsize, start_offset = *offset;
3524 int count;
3525
3526 if (countersize != sizeof(struct counter64)) {
3527 _asn_size_err("build uint64", countersize,
3528 sizeof(struct counter64));
3529 return 0;
3530 }
3531
3532 CHECK_OVERFLOW_U(high,13);
3533 CHECK_OVERFLOW_U(low,13);
3534
3535 /*
3536 * Encode the low 4 bytes first.
3537 */
3538 if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3539 return 0;
3540 }
3541 *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3542 low >>= 8;
3543 count = 1;
3544
3545 while (low != 0) {
3546 count++;
3547 if (((*pkt_len - *offset) < 1)
3548 && !(r && asn_realloc(pkt, pkt_len))) {
3549 return 0;
3550 }
3551 *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3552 low >>= 8;
3553 }
3554
3555 /*
3556 * Then the high byte if present.
3557 */
3558 if (high) {
3559 /*
3560 * Do the rest of the low byte.
3561 */
3562 for (; count < 4; count++) {
3563 if (((*pkt_len - *offset) < 1)
3564 && !(r && asn_realloc(pkt, pkt_len))) {
3565 return 0;
3566 }
3567 *(*pkt + *pkt_len - (++*offset)) = 0;
3568 }
3569
3570 /*
3571 * Do high byte.
3572 */
3573 if (((*pkt_len - *offset) < 1)
3574 && !(r && asn_realloc(pkt, pkt_len))) {
3575 return 0;
3576 }
3577 *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3578 high >>= 8;
3579
3580 while (high != 0) {
3581 if (((*pkt_len - *offset) < 1)
3582 && !(r && asn_realloc(pkt, pkt_len))) {
3583 return 0;
3584 }
3585 *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3586 high >>= 8;
3587 }
3588 }
3589
3590 if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
3591 /*
3592 * Make sure left most bit is representational of the rest of the bits
3593 * that aren't encoded.
3594 */
3595 if (((*pkt_len - *offset) < 1)
3596 && !(r && asn_realloc(pkt, pkt_len))) {
3597 return 0;
3598 }
3599 *(*pkt + *pkt_len - (++*offset)) = 0;
3600 }
3601
3602 intsize = *offset - start_offset;
3603
3604 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3605 /*
3606 * Encode a Counter64 as an opaque (it also works in SNMPv1).
3607 */
3608 if (type == ASN_OPAQUE_COUNTER64) {
3609 while ((*pkt_len - *offset) < 5) {
3610 if (!(r && asn_realloc(pkt, pkt_len))) {
3611 return 0;
3612 }
3613 }
3614
3615 *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3616 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_COUNTER64;
3617 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3618
3619 /*
3620 * Put the tag and length for the Opaque wrapper.
3621 */
3622 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3623 ASN_OPAQUE, intsize + 3)) {
3624 if (_asn_realloc_build_header_check
3625 ("build counter u64", pkt, pkt_len, intsize + 3)) {
3626 return 0;
3627 }
3628 } else {
3629 return 0;
3630 }
3631 } else if (type == ASN_OPAQUE_U64) {
3632 /*
3633 * Encode the Unsigned int64 in an opaque.
3634 */
3635 while ((*pkt_len - *offset) < 5) {
3636 if (!(r && asn_realloc(pkt, pkt_len))) {
3637 return 0;
3638 }
3639 }
3640
3641 *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3642 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_U64;
3643 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3644
3645 /*
3646 * Put the tag and length for the Opaque wrapper.
3647 */
3648 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3649 ASN_OPAQUE, intsize + 3)) {
3650 if (_asn_realloc_build_header_check
3651 ("build counter u64", pkt, pkt_len, intsize + 3)) {
3652 return 0;
3653 }
3654 } else {
3655 return 0;
3656 }
3657 } else {
3658
3659 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3660 if (asn_realloc_rbuild_header
3661 (pkt, pkt_len, offset, r, type, intsize)) {
3662 if (_asn_realloc_build_header_check
3663 ("build uint64", pkt, pkt_len, intsize)) {
3664 return 0;
3665 }
3666 } else {
3667 return 0;
3668 }
3669 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3670 }
3671 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3672
3673 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
3674 DEBUGMSG(("dumpv_send", " U64:\t%lu %lu\n", cp->high, cp->low));
3675 return 1;
3676 }
3677
3678 #ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3679
3680
3681 /**
3682 * @internal
3683 * builds an ASN object containing an signed int64.
3684 *
3685 * @see asn_build_signed_int64
3686 *
3687 * @param pkt IN/OUT address of the begining of the buffer.
3688 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3689 * @param offset IN/OUT offset to the start of the buffer where to write
3690 * @param r IN if not zero reallocate the buffer to fit the
3691 * needed size.
3692 * @param type IN - type of object
3693 * @param cp IN - pointer to counter struct
3694 * @param countersize IN - size of input buffer
3695 *
3696 * @return 1 on success, 0 on error
3697 */
3698 int
asn_realloc_rbuild_signed_int64(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,u_char type,const struct counter64 * cp,size_t countersize)3699 asn_realloc_rbuild_signed_int64(u_char ** pkt, size_t * pkt_len,
3700 size_t * offset, int r,
3701 u_char type,
3702 const struct counter64 *cp, size_t countersize)
3703 {
3704 /*
3705 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
3706 */
3707 register int32_t low = cp->low, high = cp->high;
3708 size_t intsize, start_offset = *offset;
3709 int count;
3710 int32_t testvalue = (high & 0x80000000) ? -1 : 0;
3711
3712 if (countersize != sizeof(struct counter64)) {
3713 _asn_size_err("build uint64", countersize,
3714 sizeof(struct counter64));
3715 return 0;
3716 }
3717
3718 /*
3719 * Encode the low 4 bytes first.
3720 */
3721 if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3722 return 0;
3723 }
3724 *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3725 low >>= 8;
3726 count = 1;
3727
3728 while ((int) low != testvalue && count < 4) {
3729 count++;
3730 if (((*pkt_len - *offset) < 1)
3731 && !(r && asn_realloc(pkt, pkt_len))) {
3732 return 0;
3733 }
3734 *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3735 low >>= 8;
3736 }
3737
3738 /*
3739 * Then the high byte if present.
3740 */
3741 if (high != testvalue) {
3742 /*
3743 * Do the rest of the low byte.
3744 */
3745 for (; count < 4; count++) {
3746 if (((*pkt_len - *offset) < 1)
3747 && !(r && asn_realloc(pkt, pkt_len))) {
3748 return 0;
3749 }
3750 *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
3751 }
3752
3753 /*
3754 * Do high byte.
3755 */
3756 if (((*pkt_len - *offset) < 1)
3757 && !(r && asn_realloc(pkt, pkt_len))) {
3758 return 0;
3759 }
3760 *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3761 high >>= 8;
3762
3763 while ((int) high != testvalue) {
3764 if (((*pkt_len - *offset) < 1)
3765 && !(r && asn_realloc(pkt, pkt_len))) {
3766 return 0;
3767 }
3768 *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3769 high >>= 8;
3770 }
3771 }
3772
3773 if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) {
3774 /*
3775 * Make sure left most bit is representational of the rest of the bits
3776 * that aren't encoded.
3777 */
3778 if (((*pkt_len - *offset) < 1)
3779 && !(r && asn_realloc(pkt, pkt_len))) {
3780 return 0;
3781 }
3782 *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
3783 }
3784
3785 intsize = *offset - start_offset;
3786
3787 while ((*pkt_len - *offset) < 5) {
3788 if (!(r && asn_realloc(pkt, pkt_len))) {
3789 return 0;
3790 }
3791 }
3792
3793 *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3794 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_I64;
3795 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3796
3797 /*
3798 * Put the tag and length for the Opaque wrapper.
3799 */
3800 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3801 ASN_OPAQUE, intsize + 3)) {
3802 if (_asn_realloc_build_header_check
3803 ("build counter u64", pkt, pkt_len, intsize + 3)) {
3804 return 0;
3805 }
3806 } else {
3807 return 0;
3808 }
3809
3810 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
3811 DEBUGMSG(("dumpv_send", " UInt64:\t%lu %lu\n", cp->high, cp->low));
3812 return 1;
3813 }
3814
3815 /**
3816 * @internal
3817 * builds an ASN object containing an float.
3818 *
3819 * @see asn_build_float
3820 *
3821 * @param pkt IN/OUT address of the begining of the buffer.
3822 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3823 * @param offset IN/OUT offset to the start of the buffer where to write
3824 * @param r IN if not zero reallocate the buffer to fit the
3825 * needed size.
3826 * @param type IN - type of object
3827 * @param floatp IN - pointer to the float
3828 * @param floatsize IN - size of input buffer
3829 *
3830 * @return 1 on success, 0 on error
3831 */
3832
3833 int
asn_realloc_rbuild_float(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,u_char type,const float * floatp,size_t floatsize)3834 asn_realloc_rbuild_float(u_char ** pkt, size_t * pkt_len,
3835 size_t * offset, int r,
3836 u_char type, const float *floatp, size_t floatsize)
3837 {
3838 size_t start_offset = *offset;
3839 union {
3840 float floatVal;
3841 int intVal;
3842 u_char c[sizeof(float)];
3843 } fu;
3844
3845 /*
3846 * Floatsize better not be larger than realistic.
3847 */
3848 if (floatsize != sizeof(float) || floatsize > 122) {
3849 return 0;
3850 }
3851
3852 while ((*pkt_len - *offset) < floatsize + 3) {
3853 if (!(r && asn_realloc(pkt, pkt_len))) {
3854 return 0;
3855 }
3856 }
3857
3858 /*
3859 * Correct for endian differences and copy value.
3860 */
3861 fu.floatVal = *floatp;
3862 fu.intVal = htonl(fu.intVal);
3863 *offset += floatsize;
3864 memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), floatsize);
3865
3866 /*
3867 * Put the special tag and length (3 bytes).
3868 */
3869 *(*pkt + *pkt_len - (++*offset)) = (u_char) floatsize;
3870 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_FLOAT;
3871 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3872
3873 /*
3874 * Put the tag and length for the Opaque wrapper.
3875 */
3876 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3877 ASN_OPAQUE, floatsize + 3)) {
3878 if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
3879 floatsize + 3)) {
3880 return 0;
3881 } else {
3882 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3883 *offset - start_offset);
3884 DEBUGMSG(("dumpv_send", "Opaque Float:\t%f\n", *floatp));
3885 return 1;
3886 }
3887 }
3888
3889 return 0;
3890 }
3891
3892 /**
3893 * @internal
3894 * builds an ASN object containing an double.
3895 *
3896 * @see asn_build_double
3897 *
3898 * @param pkt IN/OUT address of the begining of the buffer.
3899 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3900 * @param offset IN/OUT offset to the start of the buffer where to write
3901 * @param r IN if not zero reallocate the buffer to fit the
3902 * needed size.
3903 * @param type IN - type of object
3904 * @param doublep IN - pointer to double
3905 * @param doublesize IN - size of input buffer
3906 *
3907 * @return 1 on success, 0 on error
3908 */
3909
3910 int
asn_realloc_rbuild_double(u_char ** pkt,size_t * pkt_len,size_t * offset,int r,u_char type,const double * doublep,size_t doublesize)3911 asn_realloc_rbuild_double(u_char ** pkt, size_t * pkt_len,
3912 size_t * offset, int r,
3913 u_char type, const double *doublep, size_t doublesize)
3914 {
3915 size_t start_offset = *offset;
3916 long tmp;
3917 union {
3918 double doubleVal;
3919 int intVal[2];
3920 u_char c[sizeof(double)];
3921 } fu;
3922
3923 /*
3924 * Doublesize better not be larger than realistic.
3925 */
3926 if (doublesize != sizeof(double) || doublesize > 122) {
3927 return 0;
3928 }
3929
3930 while ((*pkt_len - *offset) < doublesize + 3) {
3931 if (!(r && asn_realloc(pkt, pkt_len))) {
3932 return 0;
3933 }
3934 }
3935
3936 /*
3937 * Correct for endian differences and copy value.
3938 */
3939 fu.doubleVal = *doublep;
3940 tmp = htonl(fu.intVal[0]);
3941 fu.intVal[0] = htonl(fu.intVal[1]);
3942 fu.intVal[1] = tmp;
3943 *offset += doublesize;
3944 memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), doublesize);
3945
3946 /*
3947 * Put the special tag and length (3 bytes).
3948 */
3949 *(*pkt + *pkt_len - (++*offset)) = (u_char) doublesize;
3950 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_DOUBLE;
3951 *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3952
3953 /*
3954 * Put the tag and length for the Opaque wrapper.
3955 */
3956 if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3957 ASN_OPAQUE, doublesize + 3)) {
3958 if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
3959 doublesize + 3)) {
3960 return 0;
3961 } else {
3962 DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3963 *offset - start_offset);
3964 DEBUGMSG(("dumpv_send", " Opaque Double:\t%f\n", *doublep));
3965 return 1;
3966 }
3967 }
3968
3969 return 0;
3970 }
3971
3972 #endif /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3973 #endif /* NETSNMP_USE_REVERSE_ASNENCODING */
3974 /**
3975 * @}
3976 */
3977