Coverage Report

Created: 2026-03-20 06:49

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
36.1k
#define CHECK_OVERFLOW_S(x,y) do {                                      \
215
36.1k
        if (x > INT32_MAX) {                                            \
216
1.67k
            DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
217
1.67k
            x &= 0xffffffff;                                            \
218
34.4k
        } else if (x < INT32_MIN) {                                     \
219
2.18k
            DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
220
2.18k
            x = 0 - (x & 0xffffffff);                                   \
221
2.18k
        }                                                               \
222
36.1k
    } while(0)
223
224
44.1k
#define CHECK_OVERFLOW_U(x,y) do {                                      \
225
44.1k
        if (x > UINT32_MAX) {                                           \
226
5.14k
            x &= 0xffffffff;                                            \
227
5.14k
            DEBUGMSG(("asn","truncating unsigned value to 32 bits (%d)\n",y)); \
228
5.14k
        }                                                               \
229
44.1k
    } 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
160
{
243
160
    char            ebuf[128];
244
245
160
    snprintf(ebuf, sizeof(ebuf),
246
160
            "%s size %lu: s/b %lu", str,
247
160
      (unsigned long)wrongsize, (unsigned long)rightsize);
248
160
    ebuf[ sizeof(ebuf)-1 ] = 0;
249
160
    ERROR_MSG(ebuf);
250
160
}
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.31k
{
263
1.31k
    char            ebuf[128];
264
265
1.31k
    snprintf(ebuf, sizeof(ebuf), "%s type %d", str, wrongtype);
266
1.31k
    ebuf[ sizeof(ebuf)-1 ] = 0;
267
1.31k
    ERROR_MSG(ebuf);
268
1.31k
}
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
607
{
282
607
    char            ebuf[128];
283
284
607
    snprintf(ebuf, sizeof(ebuf),
285
607
            "%s length %lu too large: exceeds %lu", str,
286
607
      (unsigned long)wrongsize, (unsigned long)rightsize);
287
607
    ebuf[ sizeof(ebuf)-1 ] = 0;
288
607
    ERROR_MSG(ebuf);
289
607
}
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.5k
{
302
15.5k
    char            ebuf[128];
303
304
15.5k
    snprintf(ebuf, sizeof(ebuf), "%s length %lu too short: need %lu", str,
305
15.5k
      (unsigned long)wrongsize, (unsigned long)rightsize);
306
15.5k
    ERROR_MSG(ebuf);
307
15.5k
}
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
211k
{
328
211k
    int len_len;
329
330
211k
    if (pkt_len < 1)
331
0
        return NULL;               /* always too short */
332
333
211k
    if (NULL == pkt || NULL == data_len)
334
0
        return NULL;
335
336
211k
    *data_len = 0;
337
338
211k
    if (*pkt & 0x80) {
339
        /*
340
         * long length; first byte is length of length (after masking high bit)
341
         */
342
25.5k
        len_len = (int) ((*pkt & ~0x80) + 1);
343
25.5k
        if (pkt_len < len_len)
344
1.94k
            return NULL;           /* still too short for length and data */
345
346
        /* now we know we have enough data to parse length */
347
23.5k
        if (NULL == asn_parse_length(pkt, data_len))
348
1.84k
            return NULL;           /* propagate error from asn_parse_length */
349
186k
    } else {
350
        /*
351
         * short length; first byte is the length
352
         */
353
186k
        len_len = 1;
354
186k
        *data_len = *pkt;
355
186k
    }
356
357
208k
    if ((*data_len + len_len) > pkt_len)
358
8.62k
        return NULL;
359
360
199k
    return (pkt + len_len);
361
208k
}
362
363
#if 0
364
/**
365
 * @internal
366
 * call after asn_parse_length to verify result.
367
 * 
368
 * @param str  error string
369
 * @param bufp start of buffer
370
 * @param data start of data
371
 * @param plen  ? parsed length
372
 * @param dlen  ? data/buf length
373
 * 
374
 * @return 1 on error 0 on success
375
 */
376
static
377
    int
378
_asn_parse_length_check(const char *str,
379
                        const u_char * bufp, const u_char * data,
380
                        u_long plen, size_t dlen)
381
{
382
    char            ebuf[128];
383
    size_t          header_len;
384
385
    if (bufp == NULL) {
386
        /*
387
         * error message is set 
388
         */
389
        return 1;
390
    }
391
    header_len = bufp - data;
392
    if (plen > SNMP_MAX_PACKET_LEN || header_len > SNMP_MAX_PACKET_LEN ||
393
        ((size_t) plen + header_len) > dlen) {
394
        snprintf(ebuf, sizeof(ebuf),
395
                "%s: message overflow: %d len + %d delta > %d len",
396
                str, (int) plen, (int) header_len, (int) dlen);
397
        ebuf[ sizeof(ebuf)-1 ] = 0;
398
        ERROR_MSG(ebuf);
399
        return 1;
400
    }
401
    return 0;
402
}
403
#endif
404
405
406
/**
407
 * @internal 
408
 * call after asn_build_header to verify result.
409
 * 
410
 * @param str     error string to output
411
 * @param data    data pointer to verify (NULL => error )
412
 * @param datalen  data len to check
413
 * @param typedlen  type length
414
 * 
415
 * @return 0 on success, 1 on error
416
 */
417
static
418
    int
419
_asn_build_header_check(const char *str, const u_char * data,
420
                        size_t datalen, size_t typedlen)
421
11.9k
{
422
11.9k
    char            ebuf[128];
423
424
11.9k
    if (data == NULL) {
425
        /*
426
         * error message is set 
427
         */
428
384
        return 1;
429
384
    }
430
11.5k
    if (datalen < typedlen) {
431
531
        snprintf(ebuf, sizeof(ebuf),
432
531
                "%s: bad header, length too short: %lu < %lu", str,
433
531
                (unsigned long)datalen, (unsigned long)typedlen);
434
531
        ebuf[ sizeof(ebuf)-1 ] = 0;
435
531
        ERROR_MSG(ebuf);
436
531
        return 1;
437
531
    }
438
11.0k
    return 0;
439
11.5k
}
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
5.83k
{
458
5.83k
    char            ebuf[128];
459
460
5.83k
    if (pkt == NULL || *pkt == NULL) {
461
        /*
462
         * Error message is set.  
463
         */
464
0
        return 1;
465
0
    }
466
467
5.83k
    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
5.83k
    return 0;
476
5.83k
}
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.55k
{
519
1.55k
    char            ebuf[128];
520
521
1.55k
    if (asn_length < 1) {
522
18
        snprintf(ebuf, sizeof(ebuf),
523
18
                "%s: length %d too small", str, (int) asn_length);
524
18
        ebuf[ sizeof(ebuf)-1 ] = 0;
525
18
        ERROR_MSG(ebuf);
526
18
        return 1;
527
18
    }
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.54k
    return 0;
536
1.55k
}
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
27.1k
{
564
    /*
565
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
566
     */
567
27.1k
    static const char *errpre = "parse int";
568
27.1k
    register u_char *bufp = data;
569
27.1k
    u_long          asn_length;
570
27.1k
    int             i;
571
27.1k
    union {
572
27.1k
        long          l;
573
27.1k
        unsigned char b[sizeof(long)];
574
27.1k
    } value;
575
576
27.1k
    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
27.1k
    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
27.1k
    if (*datalength < 2) {
588
289
        _asn_short_err(errpre, *datalength, 2);
589
289
        return NULL;
590
289
    }
591
592
26.8k
    *type = *bufp++;
593
26.8k
    if (*type != ASN_INTEGER) {
594
356
        _asn_type_err(errpre, *type);
595
356
        return NULL;
596
356
    }
597
598
26.4k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
599
26.4k
    if (NULL == bufp) {
600
837
        _asn_short_err(errpre, *datalength - 1, asn_length);
601
837
        return NULL;
602
837
    }
603
604
25.6k
    if ((size_t) asn_length > intsize || (int) asn_length == 0) {
605
155
        _asn_length_err(errpre, (size_t) asn_length, intsize);
606
155
        return NULL;
607
155
    }
608
609
25.4k
    *datalength -= (int) asn_length + (bufp - data);
610
611
25.4k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
612
613
25.4k
    memset(&value.b, *bufp & 0x80 ? 0xff : 0, sizeof(value.b));
614
25.4k
    if (NETSNMP_BIGENDIAN) {
615
0
        for (i = sizeof(long) - asn_length; asn_length--; i++)
616
0
            value.b[i] = *bufp++;
617
25.4k
    } else {
618
78.4k
        for (i = asn_length - 1; asn_length--; i--)
619
53.0k
            value.b[i] = *bufp++;
620
25.4k
    }
621
622
25.4k
    CHECK_OVERFLOW_S(value.l, 1);
623
624
25.4k
    DEBUGMSG(("dumpv_recv", "  Integer:\t%ld (0x%.2lX)\n", value.l, value.l));
625
626
25.4k
    *intp = value.l;
627
25.4k
    return bufp;
628
25.6k
}
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.48k
{
657
    /*
658
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
659
     */
660
7.48k
    static const char *errpre = "parse uint";
661
7.48k
    register u_char *bufp = data;
662
7.48k
    u_long          asn_length;
663
7.48k
    register u_long value = 0;
664
665
7.48k
    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.48k
    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.48k
    if (*datalength < 2) {
677
22
        _asn_short_err(errpre, *datalength, 2);
678
22
        return NULL;
679
22
    }
680
681
7.46k
    *type = *bufp++;
682
7.46k
    if (*type != ASN_COUNTER && *type != ASN_GAUGE && *type != ASN_TIMETICKS
683
1.92k
            && *type != ASN_UINTEGER) {
684
100
        _asn_type_err(errpre, *type);
685
100
        return NULL;
686
100
    }
687
688
7.36k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
689
7.36k
    if (NULL == bufp) {
690
619
        _asn_short_err(errpre, *datalength - 1, asn_length);
691
619
        return NULL;
692
619
    }
693
694
6.74k
    if ((asn_length > (intsize + 1)) || ((int) asn_length == 0) ||
695
6.62k
        ((asn_length == intsize + 1) && *bufp != 0x00)) {
696
164
        _asn_length_err(errpre, (size_t) asn_length, intsize);
697
164
        return NULL;
698
164
    }
699
6.57k
    *datalength -= (int) asn_length + (bufp - data);
700
701
6.57k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
702
703
26.9k
    while (asn_length--)
704
20.3k
        value = (value << 8) | *bufp++;
705
706
6.57k
    CHECK_OVERFLOW_U(value,2);
707
708
6.57k
    DEBUGMSG(("dumpv_recv", "  UInteger:\t%ld (0x%.2lX)\n", value, value));
709
710
6.57k
    *intp = value;
711
6.57k
    return bufp;
712
6.74k
}
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.24k
{
742
    /*
743
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
744
     */
745
8.24k
    static const char *errpre = "build int";
746
8.24k
    register long   integer;
747
8.24k
    register u_long mask;
748
8.24k
    u_char         *initdatap = data;
749
750
8.24k
    if (intsize != sizeof(long)) {
751
0
        _asn_size_err(errpre, intsize, sizeof(long));
752
0
        return NULL;
753
0
    }
754
8.24k
    integer = *intp;
755
8.24k
    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.24k
    mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
763
    /*
764
     * mask is 0xFF800000 on a big-endian machine 
765
     */
766
57.7k
    while ((((integer & mask) == 0) || ((integer & mask) == mask))
767
54.1k
           && intsize > 1) {
768
49.5k
        intsize--;
769
49.5k
        integer = (u_long)integer << 8;
770
49.5k
    }
771
8.24k
    data = asn_build_header(data, datalength, type, intsize);
772
8.24k
    if (_asn_build_header_check(errpre, data, *datalength, intsize))
773
508
        return NULL;
774
775
7.73k
    *datalength -= intsize;
776
7.73k
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
777
    /*
778
     * mask is 0xFF000000 if sizeof(long) == 4.
779
     */
780
22.9k
    while (intsize--) {
781
15.2k
        *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
782
15.2k
        integer = (u_long)integer << 8;
783
15.2k
    }
784
7.73k
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
785
7.73k
    DEBUGMSG(("dumpv_send", "  Integer:\t%ld (0x%.2lX)\n", *intp, *intp));
786
7.73k
    return data;
787
8.24k
}
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
366
{
819
    /*
820
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
821
     */
822
366
    static const char *errpre = "build uint";
823
366
    register u_long integer;
824
366
    register u_long mask;
825
366
    int             add_null_byte = 0;
826
366
    u_char         *initdatap = data;
827
828
366
    if (intsize != sizeof(long)) {
829
0
        _asn_size_err(errpre, intsize, sizeof(long));
830
0
        return NULL;
831
0
    }
832
366
    integer = *intp;
833
366
    CHECK_OVERFLOW_U(integer,4);
834
835
366
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
836
    /*
837
     * mask is 0xFF000000 on a big-endian machine 
838
     */
839
366
    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
366
    } 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
366
        mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
852
        /*
853
         * mask is 0xFF800000 on a big-endian machine 
854
         */
855
2.05k
        while ((((integer & mask) == 0) || ((integer & mask) == mask))
856
1.72k
               && intsize > 1) {
857
1.69k
            intsize--;
858
1.69k
            integer <<= 8;
859
1.69k
        }
860
366
    }
861
366
    data = asn_build_header(data, datalength, type, intsize);
862
366
    if (_asn_build_header_check(errpre, data, *datalength, intsize))
863
52
        return NULL;
864
865
314
    *datalength -= intsize;
866
314
    if (add_null_byte == 1) {
867
0
        *data++ = '\0';
868
0
        intsize--;
869
0
    }
870
314
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
871
    /*
872
     * mask is 0xFF000000 on a big-endian machine 
873
     */
874
1.35k
    while (intsize--) {
875
1.03k
        *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
876
1.03k
        integer <<= 8;
877
1.03k
    }
878
314
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
879
314
    DEBUGMSG(("dumpv_send", "  UInteger:\t%ld (0x%.2lX)\n", *intp, *intp));
880
314
    return data;
881
366
}
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.3k
{
917
13.3k
    static const char *errpre = "parse string";
918
13.3k
    u_char         *bufp = data;
919
13.3k
    u_long          asn_length;
920
921
13.3k
    if (NULL == data || NULL == datalength || NULL == type || NULL == str ||
922
13.3k
        NULL == strlength) {
923
3
        ERROR_MSG("parse string: NULL pointer");
924
3
        return NULL;
925
3
    }
926
927
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
928
13.3k
    if (*datalength < 2) {
929
576
        _asn_short_err(errpre, *datalength, 2);
930
576
        return NULL;
931
576
    }
932
933
12.7k
    *type = *bufp++;
934
12.7k
    if (*type != ASN_OCTET_STR && *type != ASN_IPADDRESS && *type != ASN_OPAQUE
935
3.65k
            && *type != ASN_NSAP) {
936
570
        _asn_type_err(errpre, *type);
937
570
        return NULL;
938
570
    }
939
940
12.2k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
941
12.2k
    if (NULL == bufp) {
942
683
        _asn_short_err(errpre, *datalength - 1, asn_length);
943
683
        return NULL;
944
683
    }
945
946
11.5k
    if (asn_length > *strlength) {
947
110
        _asn_length_err(errpre, (size_t) asn_length, *strlength);
948
110
        return NULL;
949
110
    }
950
951
11.4k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
952
953
11.4k
    memmove(str, bufp, asn_length);
954
11.4k
    if (*strlength > asn_length)
955
5.35k
        str[asn_length] = 0;
956
11.4k
    *strlength = asn_length;
957
11.4k
    *datalength -= asn_length + (bufp - data);
958
959
11.4k
    DEBUGIF("dumpv_recv") {
960
1.22k
        u_char         *buf = (u_char *) malloc(1 + asn_length);
961
1.22k
        size_t          l = (buf != NULL) ? (1 + asn_length) : 0, ol = 0;
962
963
1.22k
        if (sprint_realloc_asciistring
964
1.22k
            (&buf, &l, &ol, 1, str, asn_length)) {
965
1.22k
            DEBUGMSG(("dumpv_recv", "  String:\t%s\n", buf));
966
1.22k
        } 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.22k
        if (buf != NULL) {
975
1.22k
            free(buf);
976
1.22k
        }
977
1.22k
    }
978
979
11.4k
    return bufp + asn_length;
980
11.5k
}
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
466
{
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
466
    u_char         *initdatap = data;
1017
466
    data = asn_build_header(data, datalength, type, strlength);
1018
466
    if (_asn_build_header_check
1019
466
        ("build string", data, *datalength, strlength))
1020
49
        return NULL;
1021
1022
417
    if (strlength) {
1023
389
        if (str == NULL) {
1024
0
            memset(data, 0, strlength);
1025
389
        } else {
1026
389
            memmove(data, str, strlength);
1027
389
        }
1028
389
    }
1029
417
    *datalength -= strlength;
1030
417
    DEBUGDUMPSETUP("send", initdatap, data - initdatap + strlength);
1031
417
    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
417
    return data + strlength;
1052
466
}
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
104k
{
1078
104k
    register u_char *bufp;
1079
104k
    u_long          asn_length = 0;
1080
104k
    const char      *errpre = "parse header";
1081
1082
104k
    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
104k
    if (*datalength < 2) {
1089
2.17k
        _asn_short_err(errpre, *datalength, 2);
1090
2.17k
        return NULL;
1091
2.17k
    }
1092
1093
102k
    bufp = data;
1094
    /*
1095
     * this only works on data types < 30, i.e. no extension octets 
1096
     */
1097
102k
    if (IS_EXTENSION_ID(*bufp)) {
1098
1.30k
        ERROR_MSG("can't process ID >= 30");
1099
1.30k
        return NULL;
1100
1.30k
    }
1101
100k
    *type = *bufp++;
1102
1103
100k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1104
100k
    if (NULL == bufp) {
1105
9.25k
        _asn_short_err(errpre, *datalength - 1, asn_length);
1106
9.25k
        return NULL;
1107
9.25k
    }
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
91.6k
#endif
1119
1120
91.6k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1121
1122
91.6k
    if ((asn_length > 2) && (*type == ASN_OPAQUE) && (*bufp == ASN_OPAQUE_TAG1)) {
1123
1124
        /*
1125
         * check if 64-but counter 
1126
         */
1127
7.63k
        switch (*(bufp + 1)) {
1128
1.18k
        case ASN_OPAQUE_COUNTER64:
1129
2.71k
        case ASN_OPAQUE_U64:
1130
3.38k
        case ASN_OPAQUE_FLOAT:
1131
4.01k
        case ASN_OPAQUE_DOUBLE:
1132
6.89k
        case ASN_OPAQUE_I64:
1133
6.89k
            *type = *(bufp + 1);
1134
6.89k
            break;
1135
1136
737
        default:
1137
            /*
1138
             * just an Opaque 
1139
             */
1140
737
            *datalength = (int) asn_length;
1141
737
            return bufp;
1142
7.63k
        }
1143
        /*
1144
         * value is encoded as special format 
1145
         */
1146
6.89k
        *datalength = (int) asn_length;
1147
6.89k
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
1148
6.89k
        if (NULL == bufp) {
1149
307
            _asn_short_err("parse opaque header", *datalength - 2, asn_length);
1150
307
            return NULL;
1151
307
        }
1152
6.89k
    }
1153
90.6k
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
1154
1155
90.6k
    *datalength = (int) asn_length;
1156
1157
90.6k
    return bufp;
1158
91.6k
}
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
52.1k
{                               /* error message prefix */
1178
52.1k
    data = asn_parse_header(data, datalength, type);
1179
52.1k
    if (data && (*type != expected_type)) {
1180
2.18k
        char            ebuf[128];
1181
2.18k
        snprintf(ebuf, sizeof(ebuf),
1182
2.18k
                 "%s header type %02X: s/b %02X", estr,
1183
2.18k
                (u_char) * type, (u_char) expected_type);
1184
2.18k
        ebuf[ sizeof(ebuf)-1 ] = 0;
1185
2.18k
        ERROR_MSG(ebuf);
1186
2.18k
        return NULL;
1187
2.18k
    }
1188
49.9k
    return data;
1189
52.1k
}
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
12.1k
{
1219
12.1k
    char            ebuf[128];
1220
1221
12.1k
    if (*datalength < 1) {
1222
213
        snprintf(ebuf, sizeof(ebuf),
1223
213
                "bad header length < 1 :%lu, %lu",
1224
213
    (unsigned long)*datalength, (unsigned long)length);
1225
213
        ebuf[ sizeof(ebuf)-1 ] = 0;
1226
213
        ERROR_MSG(ebuf);
1227
213
        return NULL;
1228
213
    }
1229
11.9k
    *data++ = type;
1230
11.9k
    (*datalength)--;
1231
11.9k
    return asn_build_length(data, datalength, length);
1232
12.1k
}
1233
1234
/**
1235
 * @internal
1236
 * asn_build_sequence - builds an ASN header for a sequence with the ID and
1237
 *
1238
 * length specified.
1239
 *  On entry, datalength is input as the number of valid bytes following
1240
 *   "data".  On exit, it is returned as the number of valid bytes
1241
 *   in this object following the id and length.
1242
 *
1243
 *  This only works on data types < 30, i.e. no extension octets.
1244
 *  The maximum length is 0xFFFF;
1245
 *
1246
 *  Returns a pointer to the first byte of the contents of this object.
1247
 *  Returns NULL on any error.
1248
 *
1249
 * @param data         IN - pointer to start of object
1250
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1251
 * @param type         IN - asn type of object
1252
 * @param length       IN - length of object
1253
 *
1254
 * @return Returns a pointer to the first byte of the contents of this object.
1255
 *         Returns NULL on any error.
1256
 */
1257
u_char         *
1258
asn_build_sequence(u_char * data,
1259
                   size_t * datalength, u_char type, size_t length)
1260
11.0k
{
1261
11.0k
    static const char *errpre = "build seq";
1262
11.0k
    char            ebuf[128];
1263
1264
11.0k
    if (*datalength < 4) {
1265
879
        snprintf(ebuf, sizeof(ebuf),
1266
879
                "%s: length %d < 4: PUNT", errpre,
1267
879
                (int) *datalength);
1268
879
        ebuf[ sizeof(ebuf)-1 ] = 0;
1269
879
        ERROR_MSG(ebuf);
1270
879
        return NULL;
1271
879
    }
1272
10.1k
    *datalength -= 4;
1273
10.1k
    *data++ = type;
1274
10.1k
    *data++ = (u_char) (0x02 | ASN_LONG_LEN);
1275
10.1k
    *data++ = (u_char) ((length >> 8) & 0xFF);
1276
10.1k
    *data++ = (u_char) (length & 0xFF);
1277
10.1k
    return data;
1278
11.0k
}
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
23.5k
{
1303
23.5k
    static const char *errpre = "parse length";
1304
23.5k
    char            ebuf[128];
1305
23.5k
    register u_char lengthbyte;
1306
1307
23.5k
    if (!data || !length) {
1308
0
        ERROR_MSG("parse length: NULL pointer");
1309
0
        return NULL;
1310
0
    }
1311
23.5k
    lengthbyte = *data;
1312
1313
23.5k
    if (lengthbyte & ASN_LONG_LEN) {
1314
23.5k
        lengthbyte &= ~ASN_LONG_LEN;    /* turn MSb off */
1315
23.5k
        if (lengthbyte == 0) {
1316
323
            snprintf(ebuf, sizeof(ebuf),
1317
323
                     "%s: indefinite length not supported", errpre);
1318
323
            ebuf[ sizeof(ebuf)-1 ] = 0;
1319
323
            ERROR_MSG(ebuf);
1320
323
            return NULL;
1321
323
        }
1322
23.2k
        if (lengthbyte > sizeof(long)) {
1323
1.03k
            snprintf(ebuf, sizeof(ebuf),
1324
1.03k
                    "%s: data length %d > %lu not supported", errpre,
1325
1.03k
                    lengthbyte, (unsigned long)sizeof(long));
1326
1.03k
            ebuf[ sizeof(ebuf)-1 ] = 0;
1327
1.03k
            ERROR_MSG(ebuf);
1328
1.03k
            return NULL;
1329
1.03k
        }
1330
22.2k
        data++;
1331
22.2k
        *length = 0;            /* protect against short lengths */
1332
65.5k
        while (lengthbyte--) {
1333
43.3k
            *length <<= 8;
1334
43.3k
            *length |= *data++;
1335
43.3k
        }
1336
22.2k
        if ((long) *length < 0) {
1337
488
            snprintf(ebuf, sizeof(ebuf),
1338
488
                     "%s: negative data length %ld\n", errpre,
1339
488
                     (long) *length);
1340
488
            ebuf[ sizeof(ebuf)-1 ] = 0;
1341
488
            ERROR_MSG(ebuf);
1342
488
            return NULL;
1343
488
        }
1344
21.7k
        return data;
1345
22.2k
    } else {                    /* short asnlength */
1346
0
        *length = (long) lengthbyte;
1347
0
        return data + 1;
1348
0
    }
1349
23.5k
}
1350
1351
/**
1352
 * @internal
1353
 * asn_build_length - builds an ASN header for a length with
1354
 * length specified.
1355
 *
1356
 *  On entry, datalength is input as the number of valid bytes following
1357
 *   "data".  On exit, it is returned as the number of valid bytes
1358
 *   in this object following the length.
1359
 *
1360
 *
1361
 *  Returns a pointer to the first byte of the contents of this object.
1362
 *  Returns NULL on any error.
1363
 *
1364
 * @param data         IN - pointer to start of object
1365
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1366
 * @param length       IN - length of object
1367
 *
1368
 * @return Returns a pointer to the first byte of the contents of this object.
1369
 *         Returns NULL on any error.
1370
 */
1371
u_char         *
1372
asn_build_length(u_char * data, size_t * datalength, size_t length)
1373
11.9k
{
1374
11.9k
    static const char *errpre = "build length";
1375
11.9k
    char            ebuf[128];
1376
1377
11.9k
    u_char         *start_data = data;
1378
1379
    /*
1380
     * no indefinite lengths sent 
1381
     */
1382
11.9k
    if (length < 0x80) {
1383
11.7k
        if (*datalength < 1) {
1384
138
            snprintf(ebuf, sizeof(ebuf),
1385
138
                    "%s: bad length < 1 :%lu, %lu", errpre,
1386
138
                    (unsigned long)*datalength, (unsigned long)length);
1387
138
            ebuf[ sizeof(ebuf)-1 ] = 0;
1388
138
            ERROR_MSG(ebuf);
1389
138
            return NULL;
1390
138
        }
1391
11.6k
        *data++ = (u_char) length;
1392
11.6k
    } else if (length <= 0xFF) {
1393
53
        if (*datalength < 2) {
1394
12
            snprintf(ebuf, sizeof(ebuf),
1395
12
                    "%s: bad length < 2 :%lu, %lu", errpre,
1396
12
                    (unsigned long)*datalength, (unsigned long)length);
1397
12
            ebuf[ sizeof(ebuf)-1 ] = 0;
1398
12
            ERROR_MSG(ebuf);
1399
12
            return NULL;
1400
12
        }
1401
41
        *data++ = (u_char) (0x01 | ASN_LONG_LEN);
1402
41
        *data++ = (u_char) length;
1403
97
    } else {                    /* 0xFF < length <= 0xFFFF */
1404
97
        if (*datalength < 3) {
1405
29
            snprintf(ebuf, sizeof(ebuf),
1406
29
                    "%s: bad length < 3 :%lu, %lu", errpre,
1407
29
                    (unsigned long)*datalength, (unsigned long)length);
1408
29
            ebuf[ sizeof(ebuf)-1 ] = 0;
1409
29
            ERROR_MSG(ebuf);
1410
29
            return NULL;
1411
29
        }
1412
68
        *data++ = (u_char) (0x02 | ASN_LONG_LEN);
1413
68
        *data++ = (u_char) ((length >> 8) & 0xFF);
1414
68
        *data++ = (u_char) (length & 0xFF);
1415
68
    }
1416
11.7k
    *datalength -= (data - start_data);
1417
11.7k
    return data;
1418
1419
11.9k
}
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
38.7k
{
1451
38.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
38.7k
    register u_char *bufp = data;
1459
38.7k
    register oid   *oidp = objid + 1;
1460
38.7k
    register u_long subidentifier;
1461
38.7k
    register long   length;
1462
38.7k
    u_long          asn_length;
1463
38.7k
    size_t          original_length = *objidlength;
1464
1465
38.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
38.7k
    if (*datalength < 2) {
1472
58
        _asn_short_err(errpre, *datalength, 2);
1473
58
        return NULL;
1474
58
    }
1475
1476
38.6k
    *type = *bufp++;
1477
38.6k
    if (*type != ASN_OBJECT_ID) {
1478
119
        _asn_type_err(errpre, *type);
1479
119
        return NULL;
1480
119
    }
1481
38.5k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1482
38.5k
    if (NULL == bufp) {
1483
717
        _asn_short_err(errpre, *datalength - 1, asn_length);
1484
717
        return NULL;
1485
717
    }
1486
1487
37.8k
    *datalength -= (int) asn_length + (bufp - data);
1488
1489
37.8k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
1490
1491
    /*
1492
     * Handle invalid object identifier encodings of the form 06 00 robustly 
1493
     */
1494
37.8k
    if (asn_length == 0)
1495
27.8k
        objid[0] = objid[1] = 0;
1496
1497
37.8k
    length = asn_length;
1498
37.8k
    (*objidlength)--;           /* account for expansion of first byte */
1499
1500
85.6k
    while (length > 0 && (*objidlength)-- > 0) {
1501
48.0k
        subidentifier = 0;
1502
60.1k
        do {                    /* shift and add in low order 7 bits */
1503
60.1k
            subidentifier =
1504
60.1k
                (subidentifier << 7) + (*(u_char *) bufp & ~ASN_BIT8);
1505
60.1k
            length--;
1506
60.1k
        } while ((*(u_char *) bufp++ & ASN_BIT8) && (length > 0));        /* last byte has high bit clear */
1507
1508
48.0k
  if (length == 0) {
1509
9.90k
            u_char *last_byte = bufp - 1;
1510
9.90k
            if (*last_byte & ASN_BIT8) {
1511
                /* last byte has high bit set -> wrong BER encoded OID */
1512
102
                ERROR_MSG("subidentifier syntax error");
1513
102
                return NULL;
1514
102
            }
1515
9.90k
        }
1516
47.8k
        if (subidentifier > MAX_SUBID) {
1517
55
            ERROR_MSG("subidentifier too large");
1518
55
            return NULL;
1519
55
        }
1520
47.8k
        *oidp++ = (oid) subidentifier;
1521
47.8k
    }
1522
1523
37.6k
    if (length || oidp < objid + 1) {
1524
52
        ERROR_MSG("OID length exceeds buffer size");
1525
52
        *objidlength = original_length;
1526
52
        return NULL;
1527
52
    }
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
37.6k
    subidentifier = oidp - objid >= 2 ? objid[1] : 0;
1536
37.6k
    if (subidentifier == 0x2B) {
1537
1.29k
        objid[0] = 1;
1538
1.29k
        objid[1] = 3;
1539
36.3k
    } else {
1540
36.3k
        if (subidentifier < 40) {
1541
29.7k
            objid[0] = 0;
1542
29.7k
            objid[1] = subidentifier;
1543
29.7k
        } else if (subidentifier < 80) {
1544
2.97k
            objid[0] = 1;
1545
2.97k
            objid[1] = subidentifier - 40;
1546
3.61k
        } else {
1547
3.61k
            objid[0] = 2;
1548
3.61k
            objid[1] = subidentifier - 80;
1549
3.61k
        }
1550
36.3k
    }
1551
1552
37.6k
    *objidlength = (int) (oidp - objid);
1553
1554
37.6k
    DEBUGMSG(("dumpv_recv", "  ObjID: "));
1555
37.6k
    DEBUGMSGOID(("dumpv_recv", objid, *objidlength));
1556
37.6k
    DEBUGMSG(("dumpv_recv", "\n"));
1557
37.6k
    return bufp;
1558
37.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
18.4k
{
1563
18.4k
    unsigned int encoded_len = 0;
1564
1565
18.4k
    if (objid == 0)
1566
2.66k
        return 1;
1567
1568
64.2k
    while (objid) {
1569
48.4k
        encoded_len++;
1570
48.4k
        objid >>= 7;
1571
48.4k
    }
1572
1573
15.7k
    return encoded_len;
1574
18.4k
}
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.38k
{
1604
    /*
1605
     * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
1606
     * subidentifier ::= {leadingbyte}* lastbyte
1607
     * leadingbyte ::= 1 7bitvalue
1608
     * lastbyte ::= 0 7bitvalue
1609
     */
1610
2.38k
    size_t          asnlength;
1611
2.38k
    register u_long objid_val;
1612
2.38k
    u_long          first_objid_val;
1613
2.38k
    register int    i;
1614
2.38k
    u_char         *initdatap = data;
1615
1616
    /*
1617
     * check if there are at least 2 sub-identifiers 
1618
     */
1619
2.38k
    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.35k
    } else if (objid[0] > 2) {
1627
104
        ERROR_MSG("build objid: bad first subidentifier");
1628
104
        return NULL;
1629
2.24k
    } else if (objidlength == 1) {
1630
        /*
1631
         * encode the first value 
1632
         */
1633
20
        objid_val = objid[0] * 40;
1634
20
        objidlength = 2;
1635
2.22k
    } else {
1636
        /*
1637
         * combine the first two values 
1638
         */
1639
2.22k
        if ((objid[1] >= 40 && objid[0] < 2) ||
1640
2.21k
            objid[1] > UINT32_MAX - objid[0] * 40) {
1641
127
            ERROR_MSG("build objid: bad second subidentifier");
1642
127
            return NULL;
1643
127
        }
1644
2.10k
        objid_val = objid[0] * 40 + objid[1];
1645
2.10k
    }
1646
2.15k
    first_objid_val = objid_val;
1647
2.15k
    CHECK_OVERFLOW_U(first_objid_val, 14);
1648
1649
    /*
1650
     * ditch illegal calls now 
1651
     */
1652
2.15k
    if (objidlength > MAX_OID_LEN)
1653
8
        return NULL;
1654
1655
    /*
1656
     * calculate the number of bytes needed to store the encoded value 
1657
     */
1658
2.14k
    if (objidlength <= 1) {
1659
35
        asnlength = encoded_oid_len(first_objid_val);
1660
2.11k
    } else {
1661
2.11k
        asnlength = 0;
1662
15.7k
        for (i = 1; i < objidlength; i++) {
1663
13.6k
            objid_val = i == 1 ? first_objid_val : objid[i];
1664
13.6k
            CHECK_OVERFLOW_U(objid_val, 5);
1665
13.6k
            asnlength += encoded_oid_len(objid_val);
1666
13.6k
        }
1667
2.11k
    }
1668
1669
    /*
1670
     * store the ASN.1 tag and length 
1671
     */
1672
2.14k
    data = asn_build_header(data, datalength, type, asnlength);
1673
2.14k
    if (_asn_build_header_check("build objid", data, *datalength, asnlength))
1674
172
        return NULL;
1675
1676
    /*
1677
     * store the encoded OID value 
1678
     */
1679
1.97k
    if (objidlength <= 1) {
1680
30
        *data++ = 0;
1681
1.94k
    } else {
1682
6.77k
        for (i = 1; i < objidlength; i++) {
1683
4.82k
            unsigned int encoded_len;
1684
4.82k
            int j;
1685
1686
4.82k
            objid_val = (uint32_t)(i == 1 ? first_objid_val : objid[i]);
1687
4.82k
            encoded_len = encoded_oid_len(objid_val);
1688
12.7k
            for (j = encoded_len - 1; j >= 0; j--) {
1689
7.88k
                data[j] = (objid_val & 0x7f) |
1690
7.88k
                    (j == encoded_len - 1 ? 0 : 0x80);
1691
7.88k
                objid_val >>= 7;
1692
7.88k
            }
1693
4.82k
            data += encoded_len;
1694
4.82k
        }
1695
1.94k
    }
1696
1697
    /*
1698
     * return the length and data ptr 
1699
     */
1700
1.97k
    *datalength -= asnlength;
1701
1.97k
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1702
1.97k
    DEBUGMSG(("dumpv_send", "  ObjID: "));
1703
1.97k
    DEBUGMSGOID(("dumpv_send", objid, objidlength));
1704
1.97k
    DEBUGMSG(("dumpv_send", "\n"));
1705
1.97k
    return data;
1706
2.14k
}
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
138
{
1791
    /*
1792
     * ASN.1 null ::= 0x05 0x00
1793
     */
1794
138
    u_char         *initdatap = data;
1795
138
    data = asn_build_header(data, datalength, type, 0);
1796
138
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1797
138
    DEBUGMSG(("dumpv_send", "  NULL\n"));
1798
138
    return data;
1799
138
}
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.50k
{
1829
    /*
1830
     * bitstring ::= 0x03 asnlength unused {byte}*
1831
     */
1832
1.50k
    static const char *errpre = "parse bitstring";
1833
1.50k
    register u_char *bufp = data;
1834
1.50k
    u_long          asn_length;
1835
1836
1.50k
    if (NULL == data || NULL == datalength || NULL == type ||
1837
1.50k
        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.50k
    if (*datalength < 2) {
1844
0
        _asn_short_err(errpre, *datalength, 2);
1845
0
        return NULL;
1846
0
    }
1847
1848
1.50k
    *type = *bufp++;
1849
1.50k
    if (*type != ASN_BIT_STR) {
1850
0
        _asn_type_err(errpre, *type);
1851
0
        return NULL;
1852
0
    }
1853
1854
1.50k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1855
1.50k
    if (NULL == bufp) {
1856
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1857
0
        return NULL;
1858
0
    }
1859
1860
1.50k
    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.50k
    if (_asn_bitstring_check(errpre, asn_length, *bufp))
1865
18
        return NULL;
1866
1867
1.48k
    DEBUGDUMPSETUP("recv", data, bufp - data);
1868
1.48k
    DEBUGMSG(("dumpv_recv", "  Bitstring: "));
1869
1.48k
    DEBUGMSGHEX(("dumpv_recv", data, asn_length));
1870
1.48k
    DEBUGMSG(("dumpv_recv", "\n"));
1871
1872
1.48k
    memmove(str, bufp, asn_length);
1873
1.48k
    *strlength = (int) asn_length;
1874
1.48k
    *datalength -= (int) asn_length + (bufp - data);
1875
1.48k
    return bufp + asn_length;
1876
1.50k
}
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
55
{
1906
    /*
1907
     * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
1908
     */
1909
55
    static const char *errpre = "build bitstring";
1910
55
    if (_asn_bitstring_check
1911
55
        (errpre, strlength, (u_char)((str) ? *str :  0)))
1912
0
        return NULL;
1913
1914
55
    data = asn_build_header(data, datalength, type, strlength);
1915
55
    if (_asn_build_header_check(errpre, data, *datalength, strlength))
1916
0
        return NULL;
1917
1918
55
    if (strlength > 0 && str)
1919
55
        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
55
    *datalength -= strlength;
1926
55
    DEBUGDUMPSETUP("send", data, strlength);
1927
55
    DEBUGMSG(("dumpv_send", "  Bitstring: "));
1928
55
    DEBUGMSGHEX(("dumpv_send", data, strlength));
1929
55
    DEBUGMSG(("dumpv_send", "\n"));
1930
55
    return data + strlength;
1931
55
}
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.41k
{
1961
    /*
1962
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1963
     */
1964
5.41k
    static const char *errpre = "parse uint64";
1965
5.41k
    const int       uint64sizelimit = (4 * 2) + 1;
1966
5.41k
    register u_char *bufp = data;
1967
5.41k
    u_long          asn_length;
1968
5.41k
    register u_long low = 0, high = 0;
1969
1970
5.41k
    if (countersize != sizeof(struct counter64)) {
1971
0
        _asn_size_err(errpre, countersize, sizeof(struct counter64));
1972
0
        return NULL;
1973
0
    }
1974
1975
5.41k
    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.41k
    if (*datalength < 2) {
1982
0
        _asn_short_err(errpre, *datalength, 2);
1983
0
        return NULL;
1984
0
    }
1985
1986
5.41k
    *type = *bufp++;
1987
5.41k
    if (*type != ASN_COUNTER64
1988
2.58k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1989
2.58k
            && *type != ASN_OPAQUE
1990
5.41k
#endif
1991
5.41k
            ) {
1992
35
        _asn_type_err(errpre, *type);
1993
35
        return NULL;
1994
35
    }
1995
5.37k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1996
5.37k
    if (NULL == bufp) {
1997
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1998
0
        return NULL;
1999
0
    }
2000
2001
5.37k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2002
5.37k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2003
    /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_<type> */
2004
5.37k
    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.37k
    if ((*type == ASN_OPAQUE) &&
2013
2.54k
        (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
2014
2.49k
        (*bufp == ASN_OPAQUE_TAG1) &&
2015
2.49k
        ((*(bufp + 1) == ASN_OPAQUE_COUNTER64) ||
2016
2.49k
         (*(bufp + 1) == ASN_OPAQUE_U64))) {
2017
        /*
2018
         * change type to Counter64 or U64 
2019
         */
2020
2.49k
        *type = *(bufp + 1);
2021
        /*
2022
         * value is encoded as special format 
2023
         */
2024
2.49k
        *datalength = asn_length;
2025
2.49k
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2026
2.49k
        if (NULL == bufp) {
2027
0
            _asn_short_err("parse opaque uint64", *datalength - 2, asn_length);
2028
0
            return NULL;
2029
0
        }
2030
2.49k
    }
2031
5.37k
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2032
5.37k
    if (((int) asn_length > uint64sizelimit) ||
2033
5.30k
        (((int) asn_length == uint64sizelimit) && *bufp != 0x00)) {
2034
128
        _asn_length_err(errpre, (size_t) asn_length, uint64sizelimit);
2035
128
        return NULL;
2036
128
    }
2037
5.25k
    *datalength -= (int) asn_length + (bufp - data);
2038
15.4k
    while (asn_length--) {
2039
10.2k
        high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
2040
10.2k
        low = ((low & 0x00FFFFFF) << 8) | *bufp++;
2041
10.2k
    }
2042
2043
5.25k
    CHECK_OVERFLOW_U(high,6);
2044
5.25k
    CHECK_OVERFLOW_U(low,6);
2045
2046
5.25k
    cp->low = low;
2047
5.25k
    cp->high = high;
2048
2049
5.25k
    DEBUGIF("dumpv_recv") {
2050
83
        char            i64buf[I64CHARSZ + 1];
2051
83
        printU64(i64buf, cp);
2052
83
        DEBUGMSG(("dumpv_recv", "Counter64: %s\n", i64buf));
2053
83
    }
2054
2055
5.25k
    return bufp;
2056
5.37k
}
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
427
{
2086
    /*
2087
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
2088
     */
2089
2090
427
    uint64_t        value;
2091
427
    int             add_null_byte = 0;
2092
427
    size_t          intsize = 8;
2093
427
    u_char         *initdatap = data;
2094
2095
427
    if (countersize != sizeof(struct counter64)) {
2096
0
        _asn_size_err("build uint64", countersize, sizeof(struct counter64));
2097
0
        return NULL;
2098
0
    }
2099
2100
427
    {
2101
427
        u_long high = cp->high, low = cp->low;
2102
2103
427
        CHECK_OVERFLOW_U(high,7);
2104
427
        CHECK_OVERFLOW_U(low,7);
2105
2106
427
        value = ((uint64_t)cp->high << 32) | cp->low;
2107
427
    }
2108
2109
427
    if (value >> 63) {
2110
        /*
2111
         * if MSB is set 
2112
         */
2113
163
        add_null_byte = 1;
2114
163
        intsize++;
2115
264
    } 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
264
        static const uint64_t mask = 0xff8ull << 52;
2123
1.11k
        while (((value & mask) == 0 || (value & mask) == mask) && intsize > 1) {
2124
852
            intsize--;
2125
852
            value <<= 8;
2126
852
        }
2127
264
    }
2128
427
#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
427
    if (type == ASN_OPAQUE_COUNTER64) {
2136
        /*
2137
         * put the tag and length for the Opaque wrapper 
2138
         */
2139
49
        data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2140
49
        if (_asn_build_header_check
2141
49
            ("build counter u64", data, *datalength, intsize + 3))
2142
0
            return NULL;
2143
2144
        /*
2145
         * put the special tag and length 
2146
         */
2147
49
        *data++ = ASN_OPAQUE_TAG1;
2148
49
        *data++ = ASN_OPAQUE_COUNTER64;
2149
49
        *data++ = (u_char) intsize;
2150
49
        *datalength = *datalength - 3;
2151
49
    } else
2152
        /*
2153
         * Encode the Unsigned int64 in an opaque 
2154
         */
2155
        /*
2156
         * turn into Opaque holding special tagged value 
2157
         */
2158
378
    if (type == ASN_OPAQUE_U64) {
2159
        /*
2160
         * put the tag and length for the Opaque wrapper 
2161
         */
2162
107
        data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2163
107
        if (_asn_build_header_check
2164
107
            ("build opaque u64", data, *datalength, intsize + 3))
2165
31
            return NULL;
2166
2167
        /*
2168
         * put the special tag and length 
2169
         */
2170
76
        *data++ = ASN_OPAQUE_TAG1;
2171
76
        *data++ = ASN_OPAQUE_U64;
2172
76
        *data++ = (u_char) intsize;
2173
76
        *datalength = *datalength - 3;
2174
271
    } else {
2175
271
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2176
271
        data = asn_build_header(data, datalength, type, intsize);
2177
271
        if (_asn_build_header_check
2178
271
            ("build uint64", data, *datalength, intsize))
2179
53
            return NULL;
2180
2181
271
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2182
271
    }
2183
343
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2184
343
    *datalength -= intsize;
2185
343
    if (add_null_byte == 1) {
2186
127
        *data++ = '\0';
2187
127
        intsize--;
2188
127
    }
2189
2.35k
    while (intsize--) {
2190
2.00k
        *data++ = value >> 56;
2191
2.00k
        value <<= 8;
2192
2.00k
    }
2193
343
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2194
343
    DEBUGIF("dumpv_send") {
2195
0
        char            i64buf[I64CHARSZ + 1];
2196
0
        printU64(i64buf, cp);
2197
0
        DEBUGMSG(("dumpv_send", "%s", i64buf));
2198
0
    }
2199
343
    return data;
2200
427
}
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
2.90k
{
2234
2.90k
    static const char *errpre = "parse int64";
2235
2.90k
    const int       int64sizelimit = (4 * 2) + 1;
2236
2.90k
    char            ebuf[128];
2237
2.90k
    register u_char *bufp = data;
2238
2.90k
    u_long          asn_length;
2239
2.90k
    register u_int  low = 0, high = 0;
2240
2241
2.90k
    if (countersize != sizeof(struct counter64)) {
2242
0
        _asn_size_err(errpre, countersize, sizeof(struct counter64));
2243
0
        return NULL;
2244
0
    }
2245
2246
2.90k
    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
2.90k
    if (*datalength < 2) {
2253
0
        _asn_short_err(errpre, *datalength, 2);
2254
0
        return NULL;
2255
0
    }
2256
2257
2.90k
    *type = *bufp++;
2258
2.90k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2259
2.90k
    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
2.90k
    if (asn_length < 2) {
2266
38
        _asn_short_err(errpre, asn_length, 2);
2267
38
        return NULL;
2268
38
    }
2269
2270
2.86k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2271
2.86k
    if ((*type == ASN_OPAQUE) &&
2272
2.82k
        (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
2273
2.76k
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_I64)) {
2274
        /*
2275
         * change type to Int64 
2276
         */
2277
2.76k
        *type = *(bufp + 1);
2278
        /*
2279
         * value is encoded as special format 
2280
         */
2281
2.76k
        *datalength = asn_length;
2282
2.76k
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2283
2.76k
        if (NULL == bufp) {
2284
0
            _asn_short_err("parse opaque int64", *datalength - 2, asn_length);
2285
0
            return NULL;
2286
0
        }
2287
2.76k
    }
2288
    /*
2289
     * this should always have been true until snmp gets int64 PDU types 
2290
     */
2291
99
    else {
2292
99
        snprintf(ebuf, sizeof(ebuf),
2293
99
                "%s: wrong type: %d, len %d, buf bytes (%02X,%02X)",
2294
99
                errpre, *type, (int) asn_length, *bufp, *(bufp + 1));
2295
99
        ebuf[ sizeof(ebuf)-1 ] = 0;
2296
99
        ERROR_MSG(ebuf);
2297
99
        return NULL;
2298
99
    }
2299
2.76k
    if (((int) asn_length > int64sizelimit) ||
2300
2.76k
        (((int) asn_length == int64sizelimit) && *bufp != 0x00)) {
2301
50
        _asn_length_err(errpre, (size_t) asn_length, int64sizelimit);
2302
50
        return NULL;
2303
50
    }
2304
2.71k
    *datalength -= (int) asn_length + (bufp - data);
2305
2.71k
    if ((asn_length > 0) && (*bufp & 0x80)) {
2306
746
        low = 0xFFFFFFFFU;   /* first byte bit 1 means start the data with 1s */
2307
746
        high = 0xFFFFFF;
2308
746
    }
2309
2310
10.3k
    for ( ; asn_length; asn_length--) {
2311
7.62k
        high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
2312
7.62k
        low = ((low & 0x00FFFFFF) << 8) | *bufp++;
2313
7.62k
    }
2314
2315
2.71k
    CHECK_OVERFLOW_U(high,8);
2316
2.71k
    CHECK_OVERFLOW_U(low,8);
2317
2318
2.71k
    cp->low = low;
2319
2.71k
    cp->high = high;
2320
2321
2.71k
    DEBUGIF("dumpv_recv") {
2322
90
        char            i64buf[I64CHARSZ + 1];
2323
90
        printI64(i64buf, cp);
2324
90
        DEBUGMSG(("dumpv_recv", "Integer64: %s\n", i64buf));
2325
90
    }
2326
2327
2.71k
    return bufp;
2328
2.76k
}
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
159
{
2359
    /*
2360
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
2361
     */
2362
2363
159
    register u_int  mask, mask2;
2364
159
    u_long          low;
2365
159
    long            high; /* MUST be signed because of CHECK_OVERFLOW_S(). */
2366
159
    size_t          intsize;
2367
159
    u_char         *initdatap = data;
2368
2369
159
    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
159
    intsize = 8;
2375
159
    low = cp->low;
2376
159
    high = cp->high; /* unsigned to signed conversion */
2377
2378
159
    CHECK_OVERFLOW_S(high,9);
2379
159
    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
159
    mask = 0xFF000000U;
2388
159
    mask2 = 0xFF800000U;
2389
593
    while ((((high & mask2) == 0) || ((high & mask2) == mask2))
2390
435
           && intsize > 1) {
2391
434
        intsize--;
2392
434
        high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
2393
434
        low = (low & 0x00ffffff) << 8;
2394
434
    }
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
159
    data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2402
159
    if (_asn_build_header_check
2403
159
        ("build int64", data, *datalength, intsize + 3))
2404
29
        return NULL;
2405
2406
130
    *data++ = ASN_OPAQUE_TAG1;
2407
130
    *data++ = ASN_OPAQUE_I64;
2408
130
    *data++ = (u_char) intsize;
2409
130
    *datalength -= (3 + intsize);
2410
2411
784
    while (intsize--) {
2412
654
        *data++ = (u_char) (high >> 24);
2413
654
        high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
2414
654
        low = (low & 0x00ffffff) << 8;
2415
654
    }
2416
130
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2417
130
    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
130
    return data;
2423
159
}
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.70k
{
2452
1.70k
    static const char *errpre = "parse float";
2453
1.70k
    register u_char *bufp = data;
2454
1.70k
    u_long          asn_length;
2455
1.70k
    union {
2456
1.70k
        float           floatVal;
2457
1.70k
        long            longVal;
2458
1.70k
        u_char          c[sizeof(float)];
2459
1.70k
    } fu;
2460
2461
1.70k
    if (floatsize != sizeof(float)) {
2462
0
        _asn_size_err("parse float", floatsize, sizeof(float));
2463
0
        return NULL;
2464
0
    }
2465
2466
1.70k
    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.70k
    if (*datalength < 2) {
2473
0
        _asn_short_err(errpre, *datalength, 2);
2474
0
        return NULL;
2475
0
    }
2476
2477
1.70k
    *type = *bufp++;
2478
1.70k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2479
1.70k
    if (NULL == bufp) {
2480
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2481
0
        return NULL;
2482
0
    }
2483
2484
1.70k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2485
    /*
2486
     * the float is encoded as an opaque 
2487
     */
2488
1.70k
    if ((*type == ASN_OPAQUE) &&
2489
617
        (asn_length == ASN_OPAQUE_FLOAT_BER_LEN) &&
2490
559
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_FLOAT)) {
2491
2492
        /*
2493
         * value is encoded as special format 
2494
         */
2495
559
        *datalength = asn_length;
2496
559
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2497
559
        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
559
        *type = ASN_OPAQUE_FLOAT;
2505
559
    }
2506
2507
1.70k
    if (*type != ASN_OPAQUE_FLOAT) {
2508
58
        _asn_type_err(errpre, *type);
2509
58
        return NULL;
2510
58
    }
2511
2512
1.64k
    if (asn_length != sizeof(float)) {
2513
84
        _asn_size_err("parse seq float", asn_length, sizeof(float));
2514
84
        return NULL;
2515
84
    }
2516
2517
1.56k
    *datalength -= (int) asn_length + (bufp - data);
2518
1.56k
    memcpy(&fu.c[0], bufp, asn_length);
2519
2520
    /*
2521
     * correct for endian differences 
2522
     */
2523
1.56k
    fu.longVal = ntohl(fu.longVal);
2524
2525
1.56k
    *floatp = fu.floatVal;
2526
2527
1.56k
    DEBUGMSG(("dumpv_recv", "Opaque float: %f\n", *floatp));
2528
1.56k
    return bufp;
2529
1.64k
}
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
69
{
2559
69
    union {
2560
69
        float           floatVal;
2561
69
        int             intVal;
2562
69
        u_char          c[sizeof(float)];
2563
69
    } fu;
2564
69
    u_char         *initdatap = data;
2565
2566
69
    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
69
    data = asn_build_header(data, datalength, ASN_OPAQUE, floatsize + 3);
2581
69
    if (_asn_build_header_check
2582
69
        ("build float", data, *datalength, (floatsize + 3)))
2583
13
        return NULL;
2584
2585
    /*
2586
     * put the special tag and length 
2587
     */
2588
56
    *data++ = ASN_OPAQUE_TAG1;
2589
56
    *data++ = ASN_OPAQUE_FLOAT;
2590
56
    *data++ = (u_char) floatsize;
2591
56
    *datalength = *datalength - 3;
2592
2593
56
    fu.floatVal = *floatp;
2594
    /*
2595
     * correct for endian differences 
2596
     */
2597
56
    fu.intVal = htonl(fu.intVal);
2598
2599
56
    *datalength -= floatsize;
2600
56
    memcpy(data, &fu.c[0], floatsize);
2601
2602
56
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2603
56
    DEBUGMSG(("dumpv_send", "Opaque float: %f\n", *floatp));
2604
56
    data += floatsize;
2605
56
    return data;
2606
69
}
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.62k
{
2635
1.62k
    static const char *errpre = "parse double";
2636
1.62k
    register u_char *bufp = data;
2637
1.62k
    u_long          asn_length;
2638
1.62k
    long            tmp;
2639
1.62k
    union {
2640
1.62k
        double          doubleVal;
2641
1.62k
        int             intVal[2];
2642
1.62k
        u_char          c[sizeof(double)];
2643
1.62k
    } fu;
2644
2645
2646
1.62k
    if (doublesize != sizeof(double)) {
2647
0
        _asn_size_err("parse double", doublesize, sizeof(double));
2648
0
        return NULL;
2649
0
    }
2650
2651
1.62k
    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.62k
    if (*datalength < 2) {
2658
0
        _asn_short_err(errpre, *datalength, 2);
2659
0
        return NULL;
2660
0
    }
2661
2662
1.62k
    *type = *bufp++;
2663
1.62k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2664
1.62k
    if (NULL == bufp) {
2665
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2666
0
        return NULL;
2667
0
    }
2668
2669
1.62k
    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.62k
    if ((*type == ASN_OPAQUE) && (asn_length < 2)) {
2675
0
        _asn_short_err(errpre, asn_length, 2);
2676
0
        return NULL;
2677
0
    }
2678
1.62k
    if ((*type == ASN_OPAQUE) &&
2679
555
        (asn_length == ASN_OPAQUE_DOUBLE_BER_LEN) &&
2680
475
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_DOUBLE)) {
2681
2682
        /*
2683
         * value is encoded as special format 
2684
         */
2685
475
        *datalength = asn_length;
2686
475
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2687
475
        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
475
        *type = ASN_OPAQUE_DOUBLE;
2696
475
    }
2697
2698
1.62k
    if (*type != ASN_OPAQUE_DOUBLE) {
2699
80
        _asn_type_err(errpre, *type);
2700
80
        return NULL;
2701
80
    }
2702
2703
1.54k
    if (asn_length != sizeof(double)) {
2704
76
        _asn_size_err("parse seq double", asn_length, sizeof(double));
2705
76
        return NULL;
2706
76
    }
2707
1.46k
    *datalength -= (int) asn_length + (bufp - data);
2708
1.46k
    memcpy(&fu.c[0], bufp, asn_length);
2709
2710
    /*
2711
     * correct for endian differences 
2712
     */
2713
2714
1.46k
    tmp = ntohl(fu.intVal[0]);
2715
1.46k
    fu.intVal[0] = ntohl(fu.intVal[1]);
2716
1.46k
    fu.intVal[1] = tmp;
2717
2718
1.46k
    *doublep = fu.doubleVal;
2719
1.46k
    DEBUGMSG(("dumpv_recv", "  Opaque Double:\t%f\n", *doublep));
2720
2721
1.46k
    return bufp;
2722
1.54k
}
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
42
{
2752
42
    long            tmp;
2753
42
    union {
2754
42
        double          doubleVal;
2755
42
        int             intVal[2];
2756
42
        u_char          c[sizeof(double)];
2757
42
    } fu;
2758
42
    u_char         *initdatap = data;
2759
2760
42
    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
42
    data = asn_build_header(data, datalength, ASN_OPAQUE, doublesize + 3);
2776
42
    if (_asn_build_header_check
2777
42
        ("build double", data, *datalength, doublesize + 3))
2778
8
        return NULL;
2779
2780
    /*
2781
     * put the special tag and length 
2782
     */
2783
34
    *data++ = ASN_OPAQUE_TAG1;
2784
34
    *data++ = ASN_OPAQUE_DOUBLE;
2785
34
    *data++ = (u_char) doublesize;
2786
34
    *datalength = *datalength - 3;
2787
2788
34
    fu.doubleVal = *doublep;
2789
    /*
2790
     * correct for endian differences 
2791
     */
2792
34
    tmp = htonl(fu.intVal[0]);
2793
34
    fu.intVal[0] = htonl(fu.intVal[1]);
2794
34
    fu.intVal[1] = tmp;
2795
34
    *datalength -= doublesize;
2796
34
    memcpy(data, &fu.c[0], doublesize);
2797
2798
34
    data += doublesize;
2799
34
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2800
34
    DEBUGMSG(("dumpv_send", "  Opaque double: %f\n", *doublep));
2801
34
    return data;
2802
42
}
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
9.23k
{
2866
9.23k
    static const char *errpre = "build length";
2867
9.23k
    char            ebuf[128];
2868
9.23k
    int             tmp_int;
2869
9.23k
    size_t          start_offset = *offset;
2870
2871
9.23k
    if (length <= 0x7f) {
2872
9.18k
        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
9.18k
        *(*pkt + *pkt_len - (++*offset)) = length;
2882
9.18k
    } else {
2883
49
        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
49
        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
49
        *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
2909
49
        tmp_int = *offset - start_offset;
2910
49
        *(*pkt + *pkt_len - (++*offset)) = tmp_int | 0x80;
2911
49
    }
2912
2913
9.23k
    return 1;
2914
9.23k
}
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
9.23k
{
2938
9.23k
    char            ebuf[128];
2939
2940
9.23k
    if (asn_realloc_rbuild_length(pkt, pkt_len, offset, r, length)) {
2941
9.23k
        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
9.23k
        *(*pkt + *pkt_len - (++*offset)) = type;
2951
9.23k
        return 1;
2952
9.23k
    }
2953
0
    return 0;
2954
9.23k
}
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.25k
{
2978
2.25k
    static const char *errpre = "build int";
2979
2.25k
    register long   integer = *intp;
2980
2.25k
    int             testvalue;
2981
2.25k
    size_t          start_offset = *offset;
2982
2983
2.25k
    if (intsize != sizeof(long)) {
2984
0
        _asn_size_err(errpre, intsize, sizeof(long));
2985
0
        return 0;
2986
0
    }
2987
2988
2.25k
    CHECK_OVERFLOW_S(integer,10);
2989
2.25k
    testvalue = (integer < 0) ? -1 : 0;
2990
2991
2.25k
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
2992
0
        return 0;
2993
0
    }
2994
2.25k
    *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
2995
2.25k
    integer >>= 8;
2996
2997
4.58k
    while (integer != testvalue) {
2998
2.33k
        if (((*pkt_len - *offset) < 1)
2999
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3000
0
            return 0;
3001
0
        }
3002
2.33k
        *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3003
2.33k
        integer >>= 8;
3004
2.33k
    }
3005
3006
2.25k
    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
337
        if (((*pkt_len - *offset) < 1)
3012
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3013
0
            return 0;
3014
0
        }
3015
337
        *(*pkt + *pkt_len - (++*offset)) = testvalue & 0xff;
3016
337
    }
3017
3018
2.25k
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3019
2.25k
                                  (*offset - start_offset))) {
3020
2.25k
        if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
3021
2.25k
                                            (*offset - start_offset))) {
3022
0
            return 0;
3023
2.25k
        } else {
3024
2.25k
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3025
2.25k
                           (*offset - start_offset));
3026
2.25k
            DEBUGMSG(("dumpv_send", "  Integer:\t%ld (0x%.2lX)\n", *intp,
3027
2.25k
                      *intp));
3028
2.25k
            return 1;
3029
2.25k
        }
3030
2.25k
    }
3031
3032
0
    return 0;
3033
2.25k
}
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
729
{
3059
729
    static const char *errpre = "build string";
3060
729
    size_t          start_offset = *offset;
3061
3062
729
    while ((*pkt_len - *offset) < strlength) {
3063
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3064
0
            return 0;
3065
0
        }
3066
0
    }
3067
3068
729
    *offset += strlength;
3069
729
    if (str)
3070
729
        memcpy(*pkt + *pkt_len - *offset, str, strlength);
3071
3072
729
    if (asn_realloc_rbuild_header
3073
729
        (pkt, pkt_len, offset, r, type, strlength)) {
3074
729
        if (_asn_realloc_build_header_check
3075
729
            (errpre, pkt, pkt_len, strlength)) {
3076
0
            return 0;
3077
729
        } else {
3078
729
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3079
729
                           *offset - start_offset);
3080
729
            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
729
        }
3106
729
        return 1;
3107
729
    }
3108
3109
0
    return 0;
3110
729
}
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
308
{
3134
308
    static const char *errpre = "build uint";
3135
308
    register u_long integer = *intp;
3136
308
    size_t          start_offset = *offset;
3137
3138
308
    if (intsize != sizeof(unsigned long)) {
3139
0
        _asn_size_err(errpre, intsize, sizeof(unsigned long));
3140
0
        return 0;
3141
0
    }
3142
3143
308
    CHECK_OVERFLOW_U(integer,11);
3144
3145
308
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3146
0
        return 0;
3147
0
    }
3148
308
    *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3149
308
    integer >>= 8;
3150
3151
1.02k
    while (integer != 0) {
3152
714
        if (((*pkt_len - *offset) < 1)
3153
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3154
0
            return 0;
3155
0
        }
3156
714
        *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3157
714
        integer >>= 8;
3158
714
    }
3159
3160
308
    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
187
        if (((*pkt_len - *offset) < 1)
3166
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3167
0
            return 0;
3168
0
        }
3169
187
        *(*pkt + *pkt_len - (++*offset)) = 0;
3170
187
    }
3171
3172
308
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3173
308
                                  (*offset - start_offset))) {
3174
308
        if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
3175
308
                                            (*offset - start_offset))) {
3176
0
            return 0;
3177
308
        } else {
3178
308
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3179
308
                           (*offset - start_offset));
3180
308
            DEBUGMSG(("dumpv_send", "  UInteger:\t%lu (0x%.2lX)\n", *intp,
3181
308
                      *intp));
3182
308
            return 1;
3183
308
        }
3184
308
    }
3185
3186
0
    return 0;
3187
308
}
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.25k
{
3211
3.25k
    return asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3212
3.25k
                                     length);
3213
3.25k
}
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
7.07k
{
3229
7.07k
    netsnmp_assert(*offset <= *pkt_len);
3230
7.07k
    if (*offset >= *pkt_len && (!r || !asn_realloc(pkt, pkt_len)))
3231
0
        return 0;
3232
7.07k
    netsnmp_assert(*offset < *pkt_len);
3233
7.07k
    *(*pkt + *pkt_len - (++*offset)) = byte;
3234
7.07k
    return 1;
3235
7.07k
}
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.19k
{
3251
5.19k
    if (!store_byte(pkt, pkt_len, offset, r, subid & 0x7f))
3252
0
        return 0;
3253
3254
7.07k
    for (subid >>= 7; subid; subid >>= 7)
3255
1.87k
        if (!store_byte(pkt, pkt_len, offset, r, subid | 0x80))
3256
0
            return 0;
3257
3258
5.19k
    return 1;
3259
5.19k
}
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.72k
{
3285
    /*
3286
     * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
3287
     * subidentifier ::= {leadingbyte}* lastbyte
3288
     * leadingbyte ::= 1 7bitvalue
3289
     * lastbyte ::= 0 7bitvalue
3290
     */
3291
1.72k
    register size_t i;
3292
1.72k
    register oid    tmpint;
3293
1.72k
    size_t          start_offset = *offset;
3294
1.72k
    const char     *errpre = "build objid";
3295
3296
    /*
3297
     * Check if there are at least 2 sub-identifiers.  
3298
     */
3299
1.72k
    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.72k
    } else if (objid[0] > 2) {
3307
0
        ERROR_MSG("build objid: bad first subidentifier");
3308
0
        return 0;
3309
1.72k
    } 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.72k
    } else {
3316
5.19k
        for (i = objidlength - 1; i >= 2; i--) {
3317
3.47k
            tmpint = objid[i];
3318
3.47k
            CHECK_OVERFLOW_U(tmpint, 12);
3319
3.47k
            if (!store_uint32(pkt, pkt_len, offset, r, tmpint))
3320
0
                return 0;
3321
3.47k
        }
3322
3323
        /*
3324
         * Combine the first two values.  
3325
         */
3326
1.72k
        if ((objid[1] >= 40 && objid[0] < 2) ||
3327
1.72k
            objid[1] > UINT32_MAX - objid[0] * 40) {
3328
0
            return 0;
3329
0
        }
3330
1.72k
        if (!store_uint32(pkt, pkt_len, offset, r, objid[0] * 40 + objid[1]))
3331
0
            return 0;
3332
1.72k
    }
3333
3334
1.72k
    tmpint = *offset - start_offset;
3335
1.72k
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, tmpint)) {
3336
1.72k
        if (_asn_realloc_build_header_check(errpre, pkt, pkt_len, tmpint)) {
3337
0
            return 0;
3338
1.72k
        } else {
3339
1.72k
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), tmpint);
3340
1.72k
            DEBUGMSG(("dumpv_send", "  ObjID: "));
3341
1.72k
            DEBUGMSGOID(("dumpv_send", objid, objidlength));
3342
1.72k
            DEBUGMSG(("dumpv_send", "\n"));
3343
1.72k
            return 1;
3344
1.72k
        }
3345
1.72k
    }
3346
3347
0
    return 0;
3348
1.72k
}
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
139
{
3370
    /*
3371
     * ASN.1 null ::= 0x05 0x00
3372
     */
3373
139
    size_t          start_offset = *offset;
3374
3375
139
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 0)) {
3376
139
        DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3377
139
                       (*offset - start_offset));
3378
139
        DEBUGMSG(("dumpv_send", "  NULL\n"));
3379
139
        return 1;
3380
139
    } else {
3381
0
        return 0;
3382
0
    }
3383
139
}
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
90
{
3409
    /*
3410
     * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
3411
     */
3412
90
    static const char *errpre = "build bitstring";
3413
90
    size_t          start_offset = *offset;
3414
3415
90
    while ((*pkt_len - *offset) < strlength) {
3416
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3417
0
            return 0;
3418
0
        }
3419
0
    }
3420
3421
90
    *offset += strlength;
3422
90
    memcpy(*pkt + *pkt_len - *offset, str, strlength);
3423
3424
90
    if (asn_realloc_rbuild_header
3425
90
        (pkt, pkt_len, offset, r, type, strlength)) {
3426
90
        if (_asn_realloc_build_header_check
3427
90
            (errpre, pkt, pkt_len, strlength)) {
3428
0
            return 0;
3429
90
        } else {
3430
90
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3431
90
                           *offset - start_offset);
3432
90
            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
90
        }
3460
90
        return 1;
3461
90
    }
3462
3463
0
    return 0;
3464
90
}
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
342
{
3489
    /*
3490
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
3491
     */
3492
342
    register u_long low = cp->low, high = cp->high;
3493
342
    size_t          intsize, start_offset = *offset;
3494
342
    int             count;
3495
3496
342
    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
342
    CHECK_OVERFLOW_U(high,13);
3503
342
    CHECK_OVERFLOW_U(low,13);
3504
3505
    /*
3506
     * Encode the low 4 bytes first.  
3507
     */
3508
342
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3509
0
        return 0;
3510
0
    }
3511
342
    *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3512
342
    low >>= 8;
3513
342
    count = 1;
3514
3515
1.09k
    while (low != 0) {
3516
754
        count++;
3517
754
        if (((*pkt_len - *offset) < 1)
3518
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3519
0
            return 0;
3520
0
        }
3521
754
        *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3522
754
        low >>= 8;
3523
754
    }
3524
3525
    /*
3526
     * Then the high byte if present.  
3527
     */
3528
342
    if (high) {
3529
        /*
3530
         * Do the rest of the low byte.  
3531
         */
3532
215
        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
215
        if (((*pkt_len - *offset) < 1)
3544
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3545
0
            return 0;
3546
0
        }
3547
215
        *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3548
215
        high >>= 8;
3549
3550
625
        while (high != 0) {
3551
410
            if (((*pkt_len - *offset) < 1)
3552
0
                && !(r && asn_realloc(pkt, pkt_len))) {
3553
0
                return 0;
3554
0
            }
3555
410
            *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3556
410
            high >>= 8;
3557
410
        }
3558
215
    }
3559
3560
342
    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
209
        if (((*pkt_len - *offset) < 1)
3566
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3567
0
            return 0;
3568
0
        }
3569
209
        *(*pkt + *pkt_len - (++*offset)) = 0;
3570
209
    }
3571
3572
342
    intsize = *offset - start_offset;
3573
3574
342
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3575
    /*
3576
     * Encode a Counter64 as an opaque (it also works in SNMPv1).  
3577
     */
3578
342
    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
279
    } else if (type == ASN_OPAQUE_U64) {
3602
        /*
3603
         * Encode the Unsigned int64 in an opaque.  
3604
         */
3605
89
        while ((*pkt_len - *offset) < 5) {
3606
0
            if (!(r && asn_realloc(pkt, pkt_len))) {
3607
0
                return 0;
3608
0
            }
3609
0
        }
3610
3611
89
        *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3612
89
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_U64;
3613
89
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3614
3615
        /*
3616
         * Put the tag and length for the Opaque wrapper.  
3617
         */
3618
89
        if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3619
89
                                      ASN_OPAQUE, intsize + 3)) {
3620
89
            if (_asn_realloc_build_header_check
3621
89
                ("build counter u64", pkt, pkt_len, intsize + 3)) {
3622
0
                return 0;
3623
0
            }
3624
89
        } else {
3625
0
            return 0;
3626
0
        }
3627
190
    } else {
3628
3629
190
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3630
190
        if (asn_realloc_rbuild_header
3631
190
            (pkt, pkt_len, offset, r, type, intsize)) {
3632
190
            if (_asn_realloc_build_header_check
3633
190
                ("build uint64", pkt, pkt_len, intsize)) {
3634
0
                return 0;
3635
0
            }
3636
190
        } else {
3637
0
            return 0;
3638
0
        }
3639
190
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3640
190
    }
3641
342
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3642
3643
342
    DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
3644
342
    DEBUGMSG(("dumpv_send", "  U64:\t%lu %lu\n", cp->high, cp->low));
3645
342
    return 1;
3646
342
}
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
237
{
3674
    /*
3675
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
3676
     */
3677
237
    register int32_t low = cp->low, high = cp->high;
3678
237
    size_t           intsize, start_offset = *offset;
3679
237
    int              count;
3680
237
    int32_t          testvalue = (high & 0x80000000) ? -1 : 0;
3681
3682
237
    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
237
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3692
0
        return 0;
3693
0
    }
3694
237
    *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3695
237
    low >>= 8;
3696
237
    count = 1;
3697
3698
709
    while ((int) low != testvalue && count < 4) {
3699
472
        count++;
3700
472
        if (((*pkt_len - *offset) < 1)
3701
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3702
0
            return 0;
3703
0
        }
3704
472
        *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3705
472
        low >>= 8;
3706
472
    }
3707
3708
    /*
3709
     * Then the high byte if present.  
3710
     */
3711
237
    if (high != testvalue) {
3712
        /*
3713
         * Do the rest of the low byte.  
3714
         */
3715
358
        for (; count < 4; count++) {
3716
166
            if (((*pkt_len - *offset) < 1)
3717
0
                && !(r && asn_realloc(pkt, pkt_len))) {
3718
0
                return 0;
3719
0
            }
3720
166
            *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
3721
166
        }
3722
3723
        /*
3724
         * Do high byte.  
3725
         */
3726
192
        if (((*pkt_len - *offset) < 1)
3727
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3728
0
            return 0;
3729
0
        }
3730
192
        *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3731
192
        high >>= 8;
3732
3733
489
        while ((int) high != testvalue) {
3734
297
            if (((*pkt_len - *offset) < 1)
3735
0
                && !(r && asn_realloc(pkt, pkt_len))) {
3736
0
                return 0;
3737
0
            }
3738
297
            *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3739
297
            high >>= 8;
3740
297
        }
3741
192
    }
3742
3743
237
    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
45
        if (((*pkt_len - *offset) < 1)
3749
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3750
0
            return 0;
3751
0
        }
3752
45
        *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
3753
45
    }
3754
3755
237
    intsize = *offset - start_offset;
3756
3757
237
    while ((*pkt_len - *offset) < 5) {
3758
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3759
0
            return 0;
3760
0
        }
3761
0
    }
3762
3763
237
    *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3764
237
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_I64;
3765
237
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3766
3767
    /*
3768
     * Put the tag and length for the Opaque wrapper.  
3769
     */
3770
237
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3771
237
                                  ASN_OPAQUE, intsize + 3)) {
3772
237
        if (_asn_realloc_build_header_check
3773
237
            ("build counter u64", pkt, pkt_len, intsize + 3)) {
3774
0
            return 0;
3775
0
        }
3776
237
    } else {
3777
0
        return 0;
3778
0
    }
3779
3780
237
    DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
3781
237
    DEBUGMSG(("dumpv_send", "  UInt64:\t%lu %lu\n", cp->high, cp->low));
3782
237
    return 1;
3783
237
}
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
114
{
3808
114
    size_t          start_offset = *offset;
3809
114
    union {
3810
114
        float           floatVal;
3811
114
        int             intVal;
3812
114
        u_char          c[sizeof(float)];
3813
114
    } fu;
3814
3815
    /*
3816
     * Floatsize better not be larger than realistic.  
3817
     */
3818
114
    if (floatsize != sizeof(float) || floatsize > 122) {
3819
0
        return 0;
3820
0
    }
3821
3822
114
    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
114
    fu.floatVal = *floatp;
3832
114
    fu.intVal = htonl(fu.intVal);
3833
114
    *offset += floatsize;
3834
114
    memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), floatsize);
3835
3836
    /*
3837
     * Put the special tag and length (3 bytes).  
3838
     */
3839
114
    *(*pkt + *pkt_len - (++*offset)) = (u_char) floatsize;
3840
114
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_FLOAT;
3841
114
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3842
3843
    /*
3844
     * Put the tag and length for the Opaque wrapper.  
3845
     */
3846
114
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3847
114
                                  ASN_OPAQUE, floatsize + 3)) {
3848
114
        if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
3849
114
                                            floatsize + 3)) {
3850
0
            return 0;
3851
114
        } else {
3852
114
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3853
114
                           *offset - start_offset);
3854
114
            DEBUGMSG(("dumpv_send", "Opaque Float:\t%f\n", *floatp));
3855
114
            return 1;
3856
114
        }
3857
114
    }
3858
3859
0
    return 0;
3860
114
}
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
43
{
3885
43
    size_t          start_offset = *offset;
3886
43
    long            tmp;
3887
43
    union {
3888
43
        double          doubleVal;
3889
43
        int             intVal[2];
3890
43
        u_char          c[sizeof(double)];
3891
43
    } fu;
3892
3893
    /*
3894
     * Doublesize better not be larger than realistic.  
3895
     */
3896
43
    if (doublesize != sizeof(double) || doublesize > 122) {
3897
0
        return 0;
3898
0
    }
3899
3900
43
    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
43
    fu.doubleVal = *doublep;
3910
43
    tmp = htonl(fu.intVal[0]);
3911
43
    fu.intVal[0] = htonl(fu.intVal[1]);
3912
43
    fu.intVal[1] = tmp;
3913
43
    *offset += doublesize;
3914
43
    memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), doublesize);
3915
3916
    /*
3917
     * Put the special tag and length (3 bytes).  
3918
     */
3919
43
    *(*pkt + *pkt_len - (++*offset)) = (u_char) doublesize;
3920
43
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_DOUBLE;
3921
43
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3922
3923
    /*
3924
     * Put the tag and length for the Opaque wrapper.  
3925
     */
3926
43
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3927
43
                                  ASN_OPAQUE, doublesize + 3)) {
3928
43
        if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
3929
43
                                            doublesize + 3)) {
3930
0
            return 0;
3931
43
        } else {
3932
43
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3933
43
                           *offset - start_offset);
3934
43
            DEBUGMSG(("dumpv_send", "  Opaque Double:\t%f\n", *doublep));
3935
43
            return 1;
3936
43
        }
3937
43
    }
3938
3939
0
    return 0;
3940
43
}
3941
3942
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3943
#endif                          /*  NETSNMP_USE_REVERSE_ASNENCODING  */
3944
/**
3945
 * @}
3946
 */