Coverage Report

Created: 2026-01-16 07:03

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