Coverage Report

Created: 2026-05-30 06:40

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