Coverage Report

Created: 2026-10-17 06:54

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