Coverage Report

Created: 2026-09-04 09:22

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