Coverage Report

Created: 2023-06-07 06:42

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