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