Coverage Report

Created: 2025-08-11 06:35

/src/net-snmp/snmplib/asn1.c
Line
Count
Source (jump to first uncovered line)
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
33.6k
#define CHECK_OVERFLOW_S(x,y) do {                                      \
215
33.6k
        if (x > INT32_MAX) {                                            \
216
1.49k
            DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
217
1.49k
            x &= 0xffffffff;                                            \
218
32.1k
        } else if (x < INT32_MIN) {                                     \
219
1.90k
            DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
220
1.90k
            x = 0 - (x & 0xffffffff);                                   \
221
1.90k
        }                                                               \
222
33.6k
    } while(0)
223
224
41.5k
#define CHECK_OVERFLOW_U(x,y) do {                                      \
225
41.5k
        if (x > UINT32_MAX) {                                           \
226
5.21k
            x &= 0xffffffff;                                            \
227
5.21k
            DEBUGMSG(("asn","truncating unsigned value to 32 bits (%d)\n",y)); \
228
5.21k
        }                                                               \
229
41.5k
    } while(0)
230
231
/**
232
 * @internal
233
 * output an error for a wrong size
234
 * 
235
 * @param str        error string
236
 * @param wrongsize  wrong size
237
 * @param rightsize  expected size
238
 */
239
static
240
    void
241
_asn_size_err(const char *str, size_t wrongsize, size_t rightsize)
242
161
{
243
161
    char            ebuf[128];
244
245
161
    snprintf(ebuf, sizeof(ebuf),
246
161
            "%s size %lu: s/b %lu", str,
247
161
      (unsigned long)wrongsize, (unsigned long)rightsize);
248
161
    ebuf[ sizeof(ebuf)-1 ] = 0;
249
161
    ERROR_MSG(ebuf);
250
161
}
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.24k
{
263
1.24k
    char            ebuf[128];
264
265
1.24k
    snprintf(ebuf, sizeof(ebuf), "%s type %d", str, wrongtype);
266
1.24k
    ebuf[ sizeof(ebuf)-1 ] = 0;
267
1.24k
    ERROR_MSG(ebuf);
268
1.24k
}
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
542
{
282
542
    char            ebuf[128];
283
284
542
    snprintf(ebuf, sizeof(ebuf),
285
542
            "%s length %lu too large: exceeds %lu", str,
286
542
      (unsigned long)wrongsize, (unsigned long)rightsize);
287
542
    ebuf[ sizeof(ebuf)-1 ] = 0;
288
542
    ERROR_MSG(ebuf);
289
542
}
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
205k
{
328
205k
    int len_len;
329
330
205k
    if (pkt_len < 1)
331
0
        return NULL;               /* always too short */
332
333
205k
    if (NULL == pkt || NULL == data_len)
334
0
        return NULL;
335
336
205k
    *data_len = 0;
337
338
205k
    if (*pkt & 0x80) {
339
        /*
340
         * long length; first byte is length of length (after masking high bit)
341
         */
342
24.8k
        len_len = (int) ((*pkt & ~0x80) + 1);
343
24.8k
        if (pkt_len < len_len)
344
1.84k
            return NULL;           /* still too short for length and data */
345
346
        /* now we know we have enough data to parse length */
347
23.0k
        if (NULL == asn_parse_length(pkt, data_len))
348
1.81k
            return NULL;           /* propagate error from asn_parse_length */
349
180k
    } else {
350
        /*
351
         * short length; first byte is the length
352
         */
353
180k
        len_len = 1;
354
180k
        *data_len = *pkt;
355
180k
    }
356
357
201k
    if ((*data_len + len_len) > pkt_len)
358
8.05k
        return NULL;
359
360
193k
    return (pkt + len_len);
361
201k
}
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
10.6k
{
422
10.6k
    char            ebuf[128];
423
424
10.6k
    if (data == NULL) {
425
        /*
426
         * error message is set 
427
         */
428
354
        return 1;
429
354
    }
430
10.2k
    if (datalen < typedlen) {
431
498
        snprintf(ebuf, sizeof(ebuf),
432
498
                "%s: bad header, length too short: %lu < %lu", str,
433
498
                (unsigned long)datalen, (unsigned long)typedlen);
434
498
        ebuf[ sizeof(ebuf)-1 ] = 0;
435
498
        ERROR_MSG(ebuf);
436
498
        return 1;
437
498
    }
438
9.79k
    return 0;
439
10.2k
}
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
4.72k
{
458
4.72k
    char            ebuf[128];
459
460
4.72k
    if (pkt == NULL || *pkt == NULL) {
461
        /*
462
         * Error message is set.  
463
         */
464
0
        return 1;
465
0
    }
466
467
4.72k
    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
4.72k
    return 0;
476
4.72k
}
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.64k
{
519
1.64k
    char            ebuf[128];
520
521
1.64k
    if (asn_length < 1) {
522
22
        snprintf(ebuf, sizeof(ebuf),
523
22
                "%s: length %d too small", str, (int) asn_length);
524
22
        ebuf[ sizeof(ebuf)-1 ] = 0;
525
22
        ERROR_MSG(ebuf);
526
22
        return 1;
527
22
    }
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.61k
    return 0;
536
1.64k
}
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.0k
{
564
    /*
565
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
566
     */
567
26.0k
    static const char *errpre = "parse int";
568
26.0k
    register u_char *bufp = data;
569
26.0k
    u_long          asn_length;
570
26.0k
    int             i;
571
26.0k
    union {
572
26.0k
        long          l;
573
26.0k
        unsigned char b[sizeof(long)];
574
26.0k
    } value;
575
576
26.0k
    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.0k
    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.0k
    if (*datalength < 2) {
588
282
        _asn_short_err(errpre, *datalength, 2);
589
282
        return NULL;
590
282
    }
591
592
25.7k
    *type = *bufp++;
593
25.7k
    if (*type != ASN_INTEGER) {
594
338
        _asn_type_err(errpre, *type);
595
338
        return NULL;
596
338
    }
597
598
25.4k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
599
25.4k
    if (NULL == bufp) {
600
807
        _asn_short_err(errpre, *datalength - 1, asn_length);
601
807
        return NULL;
602
807
    }
603
604
24.6k
    if ((size_t) asn_length > intsize || (int) asn_length == 0) {
605
137
        _asn_length_err(errpre, (size_t) asn_length, intsize);
606
137
        return NULL;
607
137
    }
608
609
24.4k
    *datalength -= (int) asn_length + (bufp - data);
610
611
24.4k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
612
613
24.4k
    memset(&value.b, *bufp & 0x80 ? 0xff : 0, sizeof(value.b));
614
24.4k
    if (NETSNMP_BIGENDIAN) {
615
0
        for (i = sizeof(long) - asn_length; asn_length--; i++)
616
0
            value.b[i] = *bufp++;
617
24.4k
    } else {
618
74.0k
        for (i = asn_length - 1; asn_length--; i--)
619
49.6k
            value.b[i] = *bufp++;
620
24.4k
    }
621
622
24.4k
    CHECK_OVERFLOW_S(value.l, 1);
623
624
24.4k
    DEBUGMSG(("dumpv_recv", "  Integer:\t%ld (0x%.2lX)\n", value.l, value.l));
625
626
24.4k
    *intp = value.l;
627
24.4k
    return bufp;
628
24.6k
}
629
630
631
/**
632
 * @internal 
633
 * asn_parse_unsigned_int - pulls an unsigned long out of an ASN int type.
634
 *
635
 *  On entry, datalength is input as the number of valid bytes following
636
 *   "data".  On exit, it is returned as the number of valid bytes
637
 *   following the end of this object.
638
 *
639
 *  Returns a pointer to the first byte past the end
640
 *   of this object (i.e. the start of the next object).
641
 *  Returns NULL on any error.
642
 *  
643
 * @param data       IN - pointer to start of object
644
 * @param datalength IN/OUT - number of valid bytes left in buffer
645
 * @param type       OUT - asn type of object
646
 * @param intp       IN/OUT - pointer to start of output buffer
647
 * @param intsize    IN - size of output buffer
648
 * 
649
 * @return pointer to the first byte past the end
650
 *   of this object (i.e. the start of the next object) Returns NULL on any error
651
 */
652
u_char         *
653
asn_parse_unsigned_int(u_char * data,
654
                       size_t * datalength,
655
                       u_char * type, u_long * intp, size_t intsize)
656
7.43k
{
657
    /*
658
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
659
     */
660
7.43k
    static const char *errpre = "parse uint";
661
7.43k
    register u_char *bufp = data;
662
7.43k
    u_long          asn_length;
663
7.43k
    register u_long value = 0;
664
665
7.43k
    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.43k
    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.43k
    if (*datalength < 2) {
677
15
        _asn_short_err(errpre, *datalength, 2);
678
15
        return NULL;
679
15
    }
680
681
7.42k
    *type = *bufp++;
682
7.42k
    if (*type != ASN_COUNTER && *type != ASN_GAUGE && *type != ASN_TIMETICKS
683
7.42k
            && *type != ASN_UINTEGER) {
684
83
        _asn_type_err(errpre, *type);
685
83
        return NULL;
686
83
    }
687
688
7.33k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
689
7.33k
    if (NULL == bufp) {
690
637
        _asn_short_err(errpre, *datalength - 1, asn_length);
691
637
        return NULL;
692
637
    }
693
694
6.70k
    if ((asn_length > (intsize + 1)) || ((int) asn_length == 0) ||
695
6.70k
        ((asn_length == intsize + 1) && *bufp != 0x00)) {
696
156
        _asn_length_err(errpre, (size_t) asn_length, intsize);
697
156
        return NULL;
698
156
    }
699
6.54k
    *datalength -= (int) asn_length + (bufp - data);
700
701
6.54k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
702
703
26.6k
    while (asn_length--)
704
20.1k
        value = (value << 8) | *bufp++;
705
706
6.54k
    CHECK_OVERFLOW_U(value,2);
707
708
6.54k
    DEBUGMSG(("dumpv_recv", "  UInteger:\t%ld (0x%.2lX)\n", value, value));
709
710
6.54k
    *intp = value;
711
6.54k
    return bufp;
712
6.70k
}
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.22k
{
742
    /*
743
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
744
     */
745
7.22k
    static const char *errpre = "build int";
746
7.22k
    register long   integer;
747
7.22k
    register u_long mask;
748
7.22k
    u_char         *initdatap = data;
749
750
7.22k
    if (intsize != sizeof(long)) {
751
0
        _asn_size_err(errpre, intsize, sizeof(long));
752
0
        return NULL;
753
0
    }
754
7.22k
    integer = *intp;
755
7.22k
    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.22k
    mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
763
    /*
764
     * mask is 0xFF800000 on a big-endian machine 
765
     */
766
50.6k
    while ((((integer & mask) == 0) || ((integer & mask) == mask))
767
50.6k
           && intsize > 1) {
768
43.4k
        intsize--;
769
43.4k
        integer = (u_long)integer << 8;
770
43.4k
    }
771
7.22k
    data = asn_build_header(data, datalength, type, intsize);
772
7.22k
    if (_asn_build_header_check(errpre, data, *datalength, intsize))
773
492
        return NULL;
774
775
6.73k
    *datalength -= intsize;
776
6.73k
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
777
    /*
778
     * mask is 0xFF000000 if sizeof(long) == 4.
779
     */
780
19.7k
    while (intsize--) {
781
13.0k
        *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
782
13.0k
        integer = (u_long)integer << 8;
783
13.0k
    }
784
6.73k
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
785
6.73k
    DEBUGMSG(("dumpv_send", "  Integer:\t%ld (0x%.2lX)\n", *intp, *intp));
786
6.73k
    return data;
787
7.22k
}
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
318
{
819
    /*
820
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
821
     */
822
318
    static const char *errpre = "build uint";
823
318
    register u_long integer;
824
318
    register u_long mask;
825
318
    int             add_null_byte = 0;
826
318
    u_char         *initdatap = data;
827
828
318
    if (intsize != sizeof(long)) {
829
0
        _asn_size_err(errpre, intsize, sizeof(long));
830
0
        return NULL;
831
0
    }
832
318
    integer = *intp;
833
318
    CHECK_OVERFLOW_U(integer,4);
834
835
318
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
836
    /*
837
     * mask is 0xFF000000 on a big-endian machine 
838
     */
839
318
    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
318
    } 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
318
        mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
852
        /*
853
         * mask is 0xFF800000 on a big-endian machine 
854
         */
855
1.76k
        while ((((integer & mask) == 0) || ((integer & mask) == mask))
856
1.76k
               && intsize > 1) {
857
1.44k
            intsize--;
858
1.44k
            integer <<= 8;
859
1.44k
        }
860
318
    }
861
318
    data = asn_build_header(data, datalength, type, intsize);
862
318
    if (_asn_build_header_check(errpre, data, *datalength, intsize))
863
26
        return NULL;
864
865
292
    *datalength -= intsize;
866
292
    if (add_null_byte == 1) {
867
0
        *data++ = '\0';
868
0
        intsize--;
869
0
    }
870
292
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
871
    /*
872
     * mask is 0xFF000000 on a big-endian machine 
873
     */
874
1.28k
    while (intsize--) {
875
997
        *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(long) - 1)));
876
997
        integer <<= 8;
877
997
    }
878
292
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
879
292
    DEBUGMSG(("dumpv_send", "  UInteger:\t%ld (0x%.2lX)\n", *intp, *intp));
880
292
    return data;
881
318
}
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
12.9k
{
917
12.9k
    static const char *errpre = "parse string";
918
12.9k
    u_char         *bufp = data;
919
12.9k
    u_long          asn_length;
920
921
12.9k
    if (NULL == data || NULL == datalength || NULL == type || NULL == str ||
922
12.9k
        NULL == strlength) {
923
3
        ERROR_MSG("parse string: NULL pointer");
924
3
        return NULL;
925
3
    }
926
927
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
928
12.9k
    if (*datalength < 2) {
929
597
        _asn_short_err(errpre, *datalength, 2);
930
597
        return NULL;
931
597
    }
932
933
12.3k
    *type = *bufp++;
934
12.3k
    if (*type != ASN_OCTET_STR && *type != ASN_IPADDRESS && *type != ASN_OPAQUE
935
12.3k
            && *type != ASN_NSAP) {
936
574
        _asn_type_err(errpre, *type);
937
574
        return NULL;
938
574
    }
939
940
11.8k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
941
11.8k
    if (NULL == bufp) {
942
646
        _asn_short_err(errpre, *datalength - 1, asn_length);
943
646
        return NULL;
944
646
    }
945
946
11.1k
    if (asn_length > *strlength) {
947
118
        _asn_length_err(errpre, (size_t) asn_length, *strlength);
948
118
        return NULL;
949
118
    }
950
951
11.0k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
952
953
11.0k
    memmove(str, bufp, asn_length);
954
11.0k
    if (*strlength > asn_length)
955
5.22k
        str[asn_length] = 0;
956
11.0k
    *strlength = asn_length;
957
11.0k
    *datalength -= asn_length + (bufp - data);
958
959
11.0k
    DEBUGIF("dumpv_recv") {
960
1.22k
        u_char         *buf = (u_char *) malloc(1 + asn_length);
961
1.22k
        size_t          l = (buf != NULL) ? (1 + asn_length) : 0, ol = 0;
962
963
1.22k
        if (sprint_realloc_asciistring
964
1.22k
            (&buf, &l, &ol, 1, str, asn_length)) {
965
1.22k
            DEBUGMSG(("dumpv_recv", "  String:\t%s\n", buf));
966
1.22k
        } else {
967
0
            if (buf == NULL) {
968
0
                DEBUGMSG(("dumpv_recv", "  String:\t[TRUNCATED]\n"));
969
0
            } else {
970
0
                DEBUGMSG(("dumpv_recv", "  String:\t%s [TRUNCATED]\n",
971
0
                          buf));
972
0
            }
973
0
        }
974
1.22k
        if (buf != NULL) {
975
1.22k
            free(buf);
976
1.22k
        }
977
1.22k
    }
978
979
11.0k
    return bufp + asn_length;
980
11.1k
}
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
387
{
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
387
    u_char         *initdatap = data;
1017
387
    data = asn_build_header(data, datalength, type, strlength);
1018
387
    if (_asn_build_header_check
1019
387
        ("build string", data, *datalength, strlength))
1020
36
        return NULL;
1021
1022
351
    if (strlength) {
1023
323
        if (str == NULL) {
1024
0
            memset(data, 0, strlength);
1025
323
        } else {
1026
323
            memmove(data, str, strlength);
1027
323
        }
1028
323
    }
1029
351
    *datalength -= strlength;
1030
351
    DEBUGDUMPSETUP("send", initdatap, data - initdatap + strlength);
1031
351
    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
351
    return data + strlength;
1052
387
}
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
100k
{
1078
100k
    register u_char *bufp;
1079
100k
    u_long          asn_length = 0;
1080
100k
    const char      *errpre = "parse header";
1081
1082
100k
    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
100k
    if (*datalength < 2) {
1089
2.02k
        _asn_short_err(errpre, *datalength, 2);
1090
2.02k
        return NULL;
1091
2.02k
    }
1092
1093
98.9k
    bufp = data;
1094
    /*
1095
     * this only works on data types < 30, i.e. no extension octets 
1096
     */
1097
98.9k
    if (IS_EXTENSION_ID(*bufp)) {
1098
1.29k
        ERROR_MSG("can't process ID >= 30");
1099
1.29k
        return NULL;
1100
1.29k
    }
1101
97.6k
    *type = *bufp++;
1102
1103
97.6k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1104
97.6k
    if (NULL == bufp) {
1105
8.67k
        _asn_short_err(errpre, *datalength - 1, asn_length);
1106
8.67k
        return NULL;
1107
8.67k
    }
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
88.9k
#endif
1119
1120
88.9k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1121
1122
88.9k
    if ((asn_length > 2) && (*type == ASN_OPAQUE) && (*bufp == ASN_OPAQUE_TAG1)) {
1123
1124
        /*
1125
         * check if 64-but counter 
1126
         */
1127
7.05k
        switch (*(bufp + 1)) {
1128
1.02k
        case ASN_OPAQUE_COUNTER64:
1129
2.28k
        case ASN_OPAQUE_U64:
1130
2.77k
        case ASN_OPAQUE_FLOAT:
1131
3.40k
        case ASN_OPAQUE_DOUBLE:
1132
6.38k
        case ASN_OPAQUE_I64:
1133
6.38k
            *type = *(bufp + 1);
1134
6.38k
            break;
1135
1136
665
        default:
1137
            /*
1138
             * just an Opaque 
1139
             */
1140
665
            *datalength = (int) asn_length;
1141
665
            return bufp;
1142
7.05k
        }
1143
        /*
1144
         * value is encoded as special format 
1145
         */
1146
6.38k
        *datalength = (int) asn_length;
1147
6.38k
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
1148
6.38k
        if (NULL == bufp) {
1149
289
            _asn_short_err("parse opaque header", *datalength - 2, asn_length);
1150
289
            return NULL;
1151
289
        }
1152
6.38k
    }
1153
88.0k
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
1154
1155
88.0k
    *datalength = (int) asn_length;
1156
1157
88.0k
    return bufp;
1158
88.9k
}
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
50.6k
{                               /* error message prefix */
1178
50.6k
    data = asn_parse_header(data, datalength, type);
1179
50.6k
    if (data && (*type != expected_type)) {
1180
2.19k
        char            ebuf[128];
1181
2.19k
        snprintf(ebuf, sizeof(ebuf),
1182
2.19k
                 "%s header type %02X: s/b %02X", estr,
1183
2.19k
                (u_char) * type, (u_char) expected_type);
1184
2.19k
        ebuf[ sizeof(ebuf)-1 ] = 0;
1185
2.19k
        ERROR_MSG(ebuf);
1186
2.19k
        return NULL;
1187
2.19k
    }
1188
48.4k
    return data;
1189
50.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
10.7k
{
1219
10.7k
    char            ebuf[128];
1220
1221
10.7k
    if (*datalength < 1) {
1222
203
        snprintf(ebuf, sizeof(ebuf),
1223
203
                "bad header length < 1 :%lu, %lu",
1224
203
    (unsigned long)*datalength, (unsigned long)length);
1225
203
        ebuf[ sizeof(ebuf)-1 ] = 0;
1226
203
        ERROR_MSG(ebuf);
1227
203
        return NULL;
1228
203
    }
1229
10.5k
    *data++ = type;
1230
10.5k
    (*datalength)--;
1231
10.5k
    return asn_build_length(data, datalength, length);
1232
10.7k
}
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.0k
{
1261
10.0k
    static const char *errpre = "build seq";
1262
10.0k
    char            ebuf[128];
1263
1264
10.0k
    if (*datalength < 4) {
1265
875
        snprintf(ebuf, sizeof(ebuf),
1266
875
                "%s: length %d < 4: PUNT", errpre,
1267
875
                (int) *datalength);
1268
875
        ebuf[ sizeof(ebuf)-1 ] = 0;
1269
875
        ERROR_MSG(ebuf);
1270
875
        return NULL;
1271
875
    }
1272
9.18k
    *datalength -= 4;
1273
9.18k
    *data++ = type;
1274
9.18k
    *data++ = (u_char) (0x02 | ASN_LONG_LEN);
1275
9.18k
    *data++ = (u_char) ((length >> 8) & 0xFF);
1276
9.18k
    *data++ = (u_char) (length & 0xFF);
1277
9.18k
    return data;
1278
10.0k
}
1279
1280
/**
1281
 * @internal
1282
 * asn_parse_length - interprets the length of the current object.
1283
 *
1284
 *  On exit, length contains the value of this length field.
1285
 *
1286
 *  Returns a pointer to the first byte after this length
1287
 *  field (aka: the start of the data field).
1288
 *  Returns NULL on any error.
1289
 *
1290
 * @param data         IN - pointer to start of length field
1291
 * @param length       OUT - value of length field
1292
 *
1293
 *  @return Returns a pointer to the first byte after this length
1294
 *          field (aka: the start of the data field).
1295
 *          Returns NULL on any error.
1296
 *
1297
 * WARNING: this function does not know the length of the data
1298
*           buffer, so it can go past the end of a short buffer.
1299
 */
1300
u_char         *
1301
asn_parse_length(u_char * data, u_long * length)
1302
23.0k
{
1303
23.0k
    static const char *errpre = "parse length";
1304
23.0k
    char            ebuf[128];
1305
23.0k
    register u_char lengthbyte;
1306
1307
23.0k
    if (!data || !length) {
1308
0
        ERROR_MSG("parse length: NULL pointer");
1309
0
        return NULL;
1310
0
    }
1311
23.0k
    lengthbyte = *data;
1312
1313
23.0k
    if (lengthbyte & ASN_LONG_LEN) {
1314
23.0k
        lengthbyte &= ~ASN_LONG_LEN;    /* turn MSb off */
1315
23.0k
        if (lengthbyte == 0) {
1316
323
            snprintf(ebuf, sizeof(ebuf),
1317
323
                     "%s: indefinite length not supported", errpre);
1318
323
            ebuf[ sizeof(ebuf)-1 ] = 0;
1319
323
            ERROR_MSG(ebuf);
1320
323
            return NULL;
1321
323
        }
1322
22.6k
        if (lengthbyte > sizeof(long)) {
1323
979
            snprintf(ebuf, sizeof(ebuf),
1324
979
                    "%s: data length %d > %lu not supported", errpre,
1325
979
                    lengthbyte, (unsigned long)sizeof(long));
1326
979
            ebuf[ sizeof(ebuf)-1 ] = 0;
1327
979
            ERROR_MSG(ebuf);
1328
979
            return NULL;
1329
979
        }
1330
21.7k
        data++;
1331
21.7k
        *length = 0;            /* protect against short lengths */
1332
64.0k
        while (lengthbyte--) {
1333
42.3k
            *length <<= 8;
1334
42.3k
            *length |= *data++;
1335
42.3k
        }
1336
21.7k
        if ((long) *length < 0) {
1337
508
            snprintf(ebuf, sizeof(ebuf),
1338
508
                     "%s: negative data length %ld\n", errpre,
1339
508
                     (long) *length);
1340
508
            ebuf[ sizeof(ebuf)-1 ] = 0;
1341
508
            ERROR_MSG(ebuf);
1342
508
            return NULL;
1343
508
        }
1344
21.2k
        return data;
1345
21.7k
    } else {                    /* short asnlength */
1346
0
        *length = (long) lengthbyte;
1347
0
        return data + 1;
1348
0
    }
1349
23.0k
}
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
10.5k
{
1374
10.5k
    static const char *errpre = "build length";
1375
10.5k
    char            ebuf[128];
1376
1377
10.5k
    u_char         *start_data = data;
1378
1379
    /*
1380
     * no indefinite lengths sent 
1381
     */
1382
10.5k
    if (length < 0x80) {
1383
10.4k
        if (*datalength < 1) {
1384
129
            snprintf(ebuf, sizeof(ebuf),
1385
129
                    "%s: bad length < 1 :%lu, %lu", errpre,
1386
129
                    (unsigned long)*datalength, (unsigned long)length);
1387
129
            ebuf[ sizeof(ebuf)-1 ] = 0;
1388
129
            ERROR_MSG(ebuf);
1389
129
            return NULL;
1390
129
        }
1391
10.3k
        *data++ = (u_char) length;
1392
10.3k
    } else if (length <= 0xFF) {
1393
47
        if (*datalength < 2) {
1394
4
            snprintf(ebuf, sizeof(ebuf),
1395
4
                    "%s: bad length < 2 :%lu, %lu", errpre,
1396
4
                    (unsigned long)*datalength, (unsigned long)length);
1397
4
            ebuf[ sizeof(ebuf)-1 ] = 0;
1398
4
            ERROR_MSG(ebuf);
1399
4
            return NULL;
1400
4
        }
1401
43
        *data++ = (u_char) (0x01 | ASN_LONG_LEN);
1402
43
        *data++ = (u_char) length;
1403
88
    } else {                    /* 0xFF < length <= 0xFFFF */
1404
88
        if (*datalength < 3) {
1405
25
            snprintf(ebuf, sizeof(ebuf),
1406
25
                    "%s: bad length < 3 :%lu, %lu", errpre,
1407
25
                    (unsigned long)*datalength, (unsigned long)length);
1408
25
            ebuf[ sizeof(ebuf)-1 ] = 0;
1409
25
            ERROR_MSG(ebuf);
1410
25
            return NULL;
1411
25
        }
1412
63
        *data++ = (u_char) (0x02 | ASN_LONG_LEN);
1413
63
        *data++ = (u_char) ((length >> 8) & 0xFF);
1414
63
        *data++ = (u_char) (length & 0xFF);
1415
63
    }
1416
10.4k
    *datalength -= (data - start_data);
1417
10.4k
    return data;
1418
1419
10.5k
}
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
37.9k
{
1451
37.9k
    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
37.9k
    register u_char *bufp = data;
1459
37.9k
    register oid   *oidp = objid + 1;
1460
37.9k
    register u_long subidentifier;
1461
37.9k
    register long   length;
1462
37.9k
    u_long          asn_length;
1463
37.9k
    size_t          original_length = *objidlength;
1464
1465
37.9k
    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
37.9k
    if (*datalength < 2) {
1472
53
        _asn_short_err(errpre, *datalength, 2);
1473
53
        return NULL;
1474
53
    }
1475
1476
37.9k
    *type = *bufp++;
1477
37.9k
    if (*type != ASN_OBJECT_ID) {
1478
125
        _asn_type_err(errpre, *type);
1479
125
        return NULL;
1480
125
    }
1481
37.7k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1482
37.7k
    if (NULL == bufp) {
1483
662
        _asn_short_err(errpre, *datalength - 1, asn_length);
1484
662
        return NULL;
1485
662
    }
1486
1487
37.1k
    *datalength -= (int) asn_length + (bufp - data);
1488
1489
37.1k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
1490
1491
    /*
1492
     * Handle invalid object identifier encodings of the form 06 00 robustly 
1493
     */
1494
37.1k
    if (asn_length == 0)
1495
27.5k
        objid[0] = objid[1] = 0;
1496
1497
37.1k
    length = asn_length;
1498
37.1k
    (*objidlength)--;           /* account for expansion of first byte */
1499
1500
84.6k
    while (length > 0 && (*objidlength)-- > 0) {
1501
47.6k
        subidentifier = 0;
1502
59.2k
        do {                    /* shift and add in low order 7 bits */
1503
59.2k
            subidentifier =
1504
59.2k
                (subidentifier << 7) + (*(u_char *) bufp & ~ASN_BIT8);
1505
59.2k
            length--;
1506
59.2k
        } while ((*(u_char *) bufp++ & ASN_BIT8) && (length > 0));        /* last byte has high bit clear */
1507
1508
47.6k
  if (length == 0) {
1509
9.51k
            u_char *last_byte = bufp - 1;
1510
9.51k
            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.51k
        }
1516
47.5k
        if (subidentifier > MAX_SUBID) {
1517
48
            ERROR_MSG("subidentifier too large");
1518
48
            return NULL;
1519
48
        }
1520
47.5k
        *oidp++ = (oid) subidentifier;
1521
47.5k
    }
1522
1523
36.9k
    if (length || oidp < objid + 1) {
1524
67
        ERROR_MSG("OID length exceeds buffer size");
1525
67
        *objidlength = original_length;
1526
67
        return NULL;
1527
67
    }
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
36.9k
    subidentifier = oidp - objid >= 2 ? objid[1] : 0;
1536
36.9k
    if (subidentifier == 0x2B) {
1537
1.27k
        objid[0] = 1;
1538
1.27k
        objid[1] = 3;
1539
35.6k
    } else {
1540
35.6k
        if (subidentifier < 40) {
1541
29.4k
            objid[0] = 0;
1542
29.4k
            objid[1] = subidentifier;
1543
29.4k
        } else if (subidentifier < 80) {
1544
2.87k
            objid[0] = 1;
1545
2.87k
            objid[1] = subidentifier - 40;
1546
3.34k
        } else {
1547
3.34k
            objid[0] = 2;
1548
3.34k
            objid[1] = subidentifier - 80;
1549
3.34k
        }
1550
35.6k
    }
1551
1552
36.9k
    *objidlength = (int) (oidp - objid);
1553
1554
36.9k
    DEBUGMSG(("dumpv_recv", "  ObjID: "));
1555
36.9k
    DEBUGMSGOID(("dumpv_recv", objid, *objidlength));
1556
36.9k
    DEBUGMSG(("dumpv_recv", "\n"));
1557
36.9k
    return bufp;
1558
36.9k
}
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.22k
        return 1;
1567
1568
59.6k
    while (objid) {
1569
45.6k
        encoded_len++;
1570
45.6k
        objid >>= 7;
1571
45.6k
    }
1572
1573
14.0k
    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.09k
{
1604
    /*
1605
     * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
1606
     * subidentifier ::= {leadingbyte}* lastbyte
1607
     * leadingbyte ::= 1 7bitvalue
1608
     * lastbyte ::= 0 7bitvalue
1609
     */
1610
2.09k
    size_t          asnlength;
1611
2.09k
    register u_long objid_val;
1612
2.09k
    u_long          first_objid_val;
1613
2.09k
    register int    i;
1614
2.09k
    u_char         *initdatap = data;
1615
1616
    /*
1617
     * check if there are at least 2 sub-identifiers 
1618
     */
1619
2.09k
    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
14
        objid_val = 0;
1625
14
        objidlength = 1;
1626
2.08k
    } else if (objid[0] > 2) {
1627
89
        ERROR_MSG("build objid: bad first subidentifier");
1628
89
        return NULL;
1629
1.99k
    } else if (objidlength == 1) {
1630
        /*
1631
         * encode the first value 
1632
         */
1633
16
        objid_val = objid[0] * 40;
1634
16
        objidlength = 2;
1635
1.98k
    } else {
1636
        /*
1637
         * combine the first two values 
1638
         */
1639
1.98k
        if (objid[1] > 40 && objid[0] < 2) {
1640
7
            ERROR_MSG("build objid: bad second subidentifier");
1641
7
            return NULL;
1642
7
        }
1643
1.97k
        objid_val = objid[0] * 40 + objid[1];
1644
1.97k
    }
1645
2.00k
    first_objid_val = objid_val;
1646
2.00k
    CHECK_OVERFLOW_U(first_objid_val, 14);
1647
1648
    /*
1649
     * ditch illegal calls now 
1650
     */
1651
2.00k
    if (objidlength > MAX_OID_LEN)
1652
10
        return NULL;
1653
1654
    /*
1655
     * calculate the number of bytes needed to store the encoded value 
1656
     */
1657
1.99k
    if (objidlength <= 1) {
1658
14
        asnlength = encoded_oid_len(first_objid_val);
1659
1.97k
    } else {
1660
1.97k
        asnlength = 0;
1661
14.0k
        for (i = 1; i < objidlength; i++) {
1662
12.1k
            objid_val = i == 1 ? first_objid_val : objid[i];
1663
12.1k
            CHECK_OVERFLOW_U(objid_val, 5);
1664
12.1k
            asnlength += encoded_oid_len(objid_val);
1665
12.1k
        }
1666
1.97k
    }
1667
1668
    /*
1669
     * store the ASN.1 tag and length 
1670
     */
1671
1.99k
    data = asn_build_header(data, datalength, type, asnlength);
1672
1.99k
    if (_asn_build_header_check("build objid", data, *datalength, asnlength))
1673
176
        return NULL;
1674
1675
    /*
1676
     * store the encoded OID value 
1677
     */
1678
1.81k
    if (objidlength <= 1) {
1679
12
        *data++ = 0;
1680
1.80k
    } else {
1681
5.96k
        for (i = 1; i < objidlength; i++) {
1682
4.16k
            unsigned int encoded_len;
1683
4.16k
            int j;
1684
1685
4.16k
            objid_val = (uint32_t)(i == 1 ? first_objid_val : objid[i]);
1686
4.16k
            encoded_len = encoded_oid_len(objid_val);
1687
11.6k
            for (j = encoded_len - 1; j >= 0; j--) {
1688
7.46k
                data[j] = (objid_val & 0x7f) |
1689
7.46k
                    (j == encoded_len - 1 ? 0 : 0x80);
1690
7.46k
                objid_val >>= 7;
1691
7.46k
            }
1692
4.16k
            data += encoded_len;
1693
4.16k
        }
1694
1.80k
    }
1695
1696
    /*
1697
     * return the length and data ptr 
1698
     */
1699
1.81k
    *datalength -= asnlength;
1700
1.81k
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1701
1.81k
    DEBUGMSG(("dumpv_send", "  ObjID: "));
1702
1.81k
    DEBUGMSGOID(("dumpv_send", objid, objidlength));
1703
1.81k
    DEBUGMSG(("dumpv_send", "\n"));
1704
1.81k
    return data;
1705
1.99k
}
1706
1707
/**
1708
 * @internal
1709
 * asn_parse_null - Interprets an ASN null type.
1710
 *
1711
 *  On entry, datalength is input as the number of valid bytes following
1712
 *   "data".  On exit, it is returned as the number of valid bytes
1713
 *   following the beginning of the next object.
1714
 *
1715
 *  Returns a pointer to the first byte past the end
1716
 *   of this object (i.e. the start of the next object).
1717
 *  Returns NULL on any error.
1718
 *
1719
 * @param data         IN - pointer to start of object
1720
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1721
 * @param type         OUT - asn type of object
1722
 *  @return Returns a pointer to the first byte past the end
1723
 *          of this object (i.e. the start of the next object).
1724
 *          Returns NULL on any error.
1725
 */
1726
u_char         *
1727
asn_parse_null(u_char * data, size_t * datalength, u_char * type)
1728
0
{
1729
    /*
1730
     * ASN.1 null ::= 0x05 0x00
1731
     */
1732
0
    register u_char *bufp = data;
1733
0
    u_long          asn_length;
1734
0
    static const char *errpre = "parse null";
1735
1736
0
    if (NULL == data || NULL == datalength || NULL == type) {
1737
0
        ERROR_MSG("parse null: NULL pointer");
1738
0
        return NULL;
1739
0
    }
1740
1741
    /** need at least 2 bytes to work with: type, length  (which should be 0) */
1742
0
    if (*datalength < 2) {
1743
0
        _asn_short_err(errpre, *datalength, 2);
1744
0
        return NULL;
1745
0
    }
1746
1747
0
    *type = *bufp++;
1748
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1749
0
    if (NULL == bufp) {
1750
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1751
0
        return NULL;
1752
0
    }
1753
0
    if (asn_length != 0) {
1754
0
        ERROR_MSG("parse null: malformed ASN.1 null");
1755
0
        return NULL;
1756
0
    }
1757
1758
0
    *datalength -= (bufp - data);
1759
1760
0
    DEBUGDUMPSETUP("recv", data, bufp - data);
1761
0
    DEBUGMSG(("dumpv_recv", "  NULL\n"));
1762
1763
0
    return bufp + asn_length;
1764
0
}
1765
1766
1767
/**
1768
 * @internal
1769
 * asn_build_null - Builds an ASN null object.
1770
 *
1771
 *  On entry, datalength is input as the number of valid bytes following
1772
 *   "data".  On exit, it is returned as the number of valid bytes
1773
 *   following the beginning of the next object.
1774
 *
1775
 *  Returns a pointer to the first byte past the end
1776
 *   of this object (i.e. the start of the next object).
1777
 *  Returns NULL on any error.
1778
 *
1779
 * @param data         IN - pointer to start of object
1780
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1781
 * @param type         IN - asn type of object
1782
 * @retun  Returns a pointer to the first byte past the end
1783
 *         of this object (i.e. the start of the next object).
1784
 *         Returns NULL on any error.
1785
 *
1786
 */
1787
u_char         *
1788
asn_build_null(u_char * data, size_t * datalength, u_char type)
1789
138
{
1790
    /*
1791
     * ASN.1 null ::= 0x05 0x00
1792
     */
1793
138
    u_char         *initdatap = data;
1794
138
    data = asn_build_header(data, datalength, type, 0);
1795
138
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1796
138
    DEBUGMSG(("dumpv_send", "  NULL\n"));
1797
138
    return data;
1798
138
}
1799
1800
/**
1801
 * @internal
1802
 * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
1803
 *
1804
 *  On entry, datalength is input as the number of valid bytes following
1805
 *   "data".  On exit, it is returned as the number of valid bytes
1806
 *   following the beginning of the next object.
1807
 *
1808
 *  "string" is filled with the bit string.
1809
 *
1810
 *  Returns a pointer to the first byte past the end
1811
 *   of this object (i.e. the start of the next object).
1812
 *  Returns NULL on any error.
1813
 *
1814
 * @param data         IN - pointer to start of object
1815
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1816
 * @param type         OUT - asn type of object
1817
 * @param string       IN/OUT - pointer to start of output buffer
1818
 * @param strlength    IN/OUT - size of output buffer
1819
 * @return Returns a pointer to the first byte past the end
1820
 *         of this object (i.e. the start of the next object).
1821
 *         Returns NULL on any error.
1822
 */
1823
u_char         *
1824
asn_parse_bitstring(u_char * data,
1825
                    size_t * datalength,
1826
                    u_char * type, u_char * str, size_t * strlength)
1827
1.59k
{
1828
    /*
1829
     * bitstring ::= 0x03 asnlength unused {byte}*
1830
     */
1831
1.59k
    static const char *errpre = "parse bitstring";
1832
1.59k
    register u_char *bufp = data;
1833
1.59k
    u_long          asn_length;
1834
1835
1.59k
    if (NULL == data || NULL == datalength || NULL == type ||
1836
1.59k
        NULL == str || NULL == strlength) {
1837
0
        ERROR_MSG("parse bitstring: NULL pointer");
1838
0
        return NULL;
1839
0
    }
1840
1841
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
1842
1.59k
    if (*datalength < 2) {
1843
0
        _asn_short_err(errpre, *datalength, 2);
1844
0
        return NULL;
1845
0
    }
1846
1847
1.59k
    *type = *bufp++;
1848
1.59k
    if (*type != ASN_BIT_STR) {
1849
0
        _asn_type_err(errpre, *type);
1850
0
        return NULL;
1851
0
    }
1852
1853
1.59k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1854
1.59k
    if (NULL == bufp) {
1855
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1856
0
        return NULL;
1857
0
    }
1858
1859
1.59k
    if ((size_t) asn_length > *strlength) {
1860
0
        _asn_length_err(errpre, (size_t) asn_length, *strlength);
1861
0
        return NULL;
1862
0
    }
1863
1.59k
    if (_asn_bitstring_check(errpre, asn_length, *bufp))
1864
22
        return NULL;
1865
1866
1.57k
    DEBUGDUMPSETUP("recv", data, bufp - data);
1867
1.57k
    DEBUGMSG(("dumpv_recv", "  Bitstring: "));
1868
1.57k
    DEBUGMSGHEX(("dumpv_recv", data, asn_length));
1869
1.57k
    DEBUGMSG(("dumpv_recv", "\n"));
1870
1871
1.57k
    memmove(str, bufp, asn_length);
1872
1.57k
    *strlength = (int) asn_length;
1873
1.57k
    *datalength -= (int) asn_length + (bufp - data);
1874
1.57k
    return bufp + asn_length;
1875
1.59k
}
1876
1877
1878
/**
1879
 * @internal
1880
 * asn_build_bitstring - Builds an ASN bit string object containing the
1881
 * input string.
1882
 *
1883
 *  On entry, datalength is input as the number of valid bytes following
1884
 *   "data".  On exit, it is returned as the number of valid bytes
1885
 *   following the beginning of the next object.
1886
 *
1887
 *  Returns a pointer to the first byte past the end
1888
 *   of this object (i.e. the start of the next object).
1889
 *  Returns NULL on any error.
1890
 *
1891
 * @param data         IN - pointer to start of object
1892
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1893
 * @param type         IN - asn type of object
1894
 * @param string       IN - pointer to start of input buffer
1895
 * @param strlength    IN - size of input buffer
1896
 * @return Returns a pointer to the first byte past the end
1897
 *         of this object (i.e. the start of the next object).
1898
 *         Returns NULL on any error.
1899
 */
1900
u_char         *
1901
asn_build_bitstring(u_char * data,
1902
                    size_t * datalength,
1903
                    u_char type, const u_char * str, size_t strlength)
1904
45
{
1905
    /*
1906
     * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
1907
     */
1908
45
    static const char *errpre = "build bitstring";
1909
45
    if (_asn_bitstring_check
1910
45
        (errpre, strlength, (u_char)((str) ? *str :  0)))
1911
0
        return NULL;
1912
1913
45
    data = asn_build_header(data, datalength, type, strlength);
1914
45
    if (_asn_build_header_check(errpre, data, *datalength, strlength))
1915
0
        return NULL;
1916
1917
45
    if (strlength > 0 && str)
1918
45
        memmove(data, str, strlength);
1919
0
    else if (strlength > 0 && !str) {
1920
0
        ERROR_MSG("no string passed into asn_build_bitstring\n");
1921
0
        return NULL;
1922
0
    }
1923
1924
45
    *datalength -= strlength;
1925
45
    DEBUGDUMPSETUP("send", data, strlength);
1926
45
    DEBUGMSG(("dumpv_send", "  Bitstring: "));
1927
45
    DEBUGMSGHEX(("dumpv_send", data, strlength));
1928
45
    DEBUGMSG(("dumpv_send", "\n"));
1929
45
    return data + strlength;
1930
45
}
1931
1932
/**
1933
 * @internal
1934
 * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
1935
 * type.
1936
 *
1937
 *  On entry, datalength is input as the number of valid bytes following
1938
 *   "data".  On exit, it is returned as the number of valid bytes
1939
 *   following the end of this object.
1940
 *
1941
 *  Returns a pointer to the first byte past the end
1942
 *   of this object (i.e. the start of the next object).
1943
 *  Returns NULL on any error.
1944
 *
1945
 * @param data         IN - pointer to start of object
1946
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1947
 * @param type         OUT - asn type of object
1948
 * @param cp           IN/OUT - pointer to counter struct
1949
 * @param countersize  IN - size of output buffer
1950
 * @return  Returns a pointer to the first byte past the end
1951
 *          of this object (i.e. the start of the next object).
1952
 *          Returns NULL on any error.
1953
 */
1954
u_char         *
1955
asn_parse_unsigned_int64(u_char * data,
1956
                         size_t * datalength,
1957
                         u_char * type,
1958
                         struct counter64 *cp, size_t countersize)
1959
5.15k
{
1960
    /*
1961
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1962
     */
1963
5.15k
    static const char *errpre = "parse uint64";
1964
5.15k
    const int       uint64sizelimit = (4 * 2) + 1;
1965
5.15k
    register u_char *bufp = data;
1966
5.15k
    u_long          asn_length;
1967
5.15k
    register u_long low = 0, high = 0;
1968
1969
5.15k
    if (countersize != sizeof(struct counter64)) {
1970
0
        _asn_size_err(errpre, countersize, sizeof(struct counter64));
1971
0
        return NULL;
1972
0
    }
1973
1974
5.15k
    if (NULL == data || NULL == datalength || NULL == type || NULL == cp) {
1975
0
        ERROR_MSG("parse uint64: NULL pointer");
1976
0
        return NULL;
1977
0
    }
1978
1979
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
1980
5.15k
    if (*datalength < 2) {
1981
0
        _asn_short_err(errpre, *datalength, 2);
1982
0
        return NULL;
1983
0
    }
1984
1985
5.15k
    *type = *bufp++;
1986
5.15k
    if (*type != ASN_COUNTER64
1987
5.15k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1988
5.15k
            && *type != ASN_OPAQUE
1989
5.15k
#endif
1990
5.15k
            ) {
1991
36
        _asn_type_err(errpre, *type);
1992
36
        return NULL;
1993
36
    }
1994
5.12k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1995
5.12k
    if (NULL == bufp) {
1996
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1997
0
        return NULL;
1998
0
    }
1999
2000
5.12k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2001
5.12k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2002
    /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_<type> */
2003
5.12k
    if ((*type == ASN_OPAQUE) && (asn_length < 2)) {
2004
0
        _asn_short_err(errpre, asn_length, 2);
2005
0
        return NULL;
2006
0
    }
2007
2008
    /*
2009
     * 64 bit counters as opaque 
2010
     */
2011
5.12k
    if ((*type == ASN_OPAQUE) &&
2012
5.12k
        (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
2013
5.12k
        (*bufp == ASN_OPAQUE_TAG1) &&
2014
5.12k
        ((*(bufp + 1) == ASN_OPAQUE_COUNTER64) ||
2015
2.08k
         (*(bufp + 1) == ASN_OPAQUE_U64))) {
2016
        /*
2017
         * change type to Counter64 or U64 
2018
         */
2019
2.08k
        *type = *(bufp + 1);
2020
        /*
2021
         * value is encoded as special format 
2022
         */
2023
2.08k
        *datalength = asn_length;
2024
2.08k
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2025
2.08k
        if (NULL == bufp) {
2026
0
            _asn_short_err("parse opaque uint64", *datalength - 2, asn_length);
2027
0
            return NULL;
2028
0
        }
2029
2.08k
    }
2030
5.12k
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2031
5.12k
    if (((int) asn_length > uint64sizelimit) ||
2032
5.12k
        (((int) asn_length == uint64sizelimit) && *bufp != 0x00)) {
2033
114
        _asn_length_err(errpre, (size_t) asn_length, uint64sizelimit);
2034
114
        return NULL;
2035
114
    }
2036
5.00k
    *datalength -= (int) asn_length + (bufp - data);
2037
15.2k
    while (asn_length--) {
2038
10.1k
        high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
2039
10.1k
        low = ((low & 0x00FFFFFF) << 8) | *bufp++;
2040
10.1k
    }
2041
2042
5.00k
    CHECK_OVERFLOW_U(high,6);
2043
5.00k
    CHECK_OVERFLOW_U(low,6);
2044
2045
5.00k
    cp->low = low;
2046
5.00k
    cp->high = high;
2047
2048
5.00k
    DEBUGIF("dumpv_recv") {
2049
105
        char            i64buf[I64CHARSZ + 1];
2050
105
        printU64(i64buf, cp);
2051
105
        DEBUGMSG(("dumpv_recv", "Counter64: %s\n", i64buf));
2052
105
    }
2053
2054
5.00k
    return bufp;
2055
5.12k
}
2056
2057
2058
/**
2059
 * @internal
2060
 * asn_build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
2061
 *
2062
 *  On entry, datalength is input as the number of valid bytes following
2063
 *   "data".  On exit, it is returned as the number of valid bytes
2064
 *   following the end of this object.
2065
 *
2066
 *  Returns a pointer to the first byte past the end
2067
 *   of this object (i.e. the start of the next object).
2068
 *  Returns NULL on any error.
2069
 *
2070
 * @param data         IN - pointer to start of output buffer
2071
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2072
 * @param type         IN  - asn type of object
2073
 * @param cp           IN - pointer to counter struct
2074
 * @param countersize  IN - size of input buffer
2075
 * @return  Returns a pointer to the first byte past the end
2076
 *          of this object (i.e. the start of the next object).
2077
 *          Returns NULL on any error.
2078
 */
2079
u_char         *
2080
asn_build_unsigned_int64(u_char * data,
2081
                         size_t * datalength,
2082
                         u_char type,
2083
                         const struct counter64 *cp, size_t countersize)
2084
418
{
2085
    /*
2086
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
2087
     */
2088
2089
418
    uint64_t        value;
2090
418
    int             add_null_byte = 0;
2091
418
    size_t          intsize = 8;
2092
418
    u_char         *initdatap = data;
2093
2094
418
    if (countersize != sizeof(struct counter64)) {
2095
0
        _asn_size_err("build uint64", countersize, sizeof(struct counter64));
2096
0
        return NULL;
2097
0
    }
2098
2099
418
    {
2100
418
        u_long high = cp->high, low = cp->low;
2101
2102
418
        CHECK_OVERFLOW_U(high,7);
2103
418
        CHECK_OVERFLOW_U(low,7);
2104
2105
418
        value = ((uint64_t)cp->high << 32) | cp->low;
2106
418
    }
2107
2108
418
    if (value >> 63) {
2109
        /*
2110
         * if MSB is set 
2111
         */
2112
170
        add_null_byte = 1;
2113
170
        intsize++;
2114
248
    } else {
2115
        /*
2116
         * Truncate "unnecessary" bytes off of the most significant end of this
2117
         * 2's complement integer.
2118
         * There should be no sequence of 9 consecutive 1's or 0's at the most
2119
         * significant end of the integer.
2120
         */
2121
248
        static const uint64_t mask = 0xff8ull << 52;
2122
1.03k
        while (((value & mask) == 0 || (value & mask) == mask) && intsize > 1) {
2123
783
            intsize--;
2124
783
            value <<= 8;
2125
783
        }
2126
248
    }
2127
418
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2128
    /*
2129
     * encode a Counter64 as an opaque (it also works in SNMPv1) 
2130
     */
2131
    /*
2132
     * turn into Opaque holding special tagged value 
2133
     */
2134
418
    if (type == ASN_OPAQUE_COUNTER64) {
2135
        /*
2136
         * put the tag and length for the Opaque wrapper 
2137
         */
2138
35
        data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2139
35
        if (_asn_build_header_check
2140
35
            ("build counter u64", data, *datalength, intsize + 3))
2141
0
            return NULL;
2142
2143
        /*
2144
         * put the special tag and length 
2145
         */
2146
35
        *data++ = ASN_OPAQUE_TAG1;
2147
35
        *data++ = ASN_OPAQUE_COUNTER64;
2148
35
        *data++ = (u_char) intsize;
2149
35
        *datalength = *datalength - 3;
2150
35
    } else
2151
        /*
2152
         * Encode the Unsigned int64 in an opaque 
2153
         */
2154
        /*
2155
         * turn into Opaque holding special tagged value 
2156
         */
2157
383
    if (type == ASN_OPAQUE_U64) {
2158
        /*
2159
         * put the tag and length for the Opaque wrapper 
2160
         */
2161
108
        data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2162
108
        if (_asn_build_header_check
2163
108
            ("build opaque u64", data, *datalength, intsize + 3))
2164
25
            return NULL;
2165
2166
        /*
2167
         * put the special tag and length 
2168
         */
2169
83
        *data++ = ASN_OPAQUE_TAG1;
2170
83
        *data++ = ASN_OPAQUE_U64;
2171
83
        *data++ = (u_char) intsize;
2172
83
        *datalength = *datalength - 3;
2173
275
    } else {
2174
275
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2175
275
        data = asn_build_header(data, datalength, type, intsize);
2176
275
        if (_asn_build_header_check
2177
275
            ("build uint64", data, *datalength, intsize))
2178
52
            return NULL;
2179
2180
275
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2181
275
    }
2182
341
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2183
341
    *datalength -= intsize;
2184
341
    if (add_null_byte == 1) {
2185
133
        *data++ = '\0';
2186
133
        intsize--;
2187
133
    }
2188
2.36k
    while (intsize--) {
2189
2.02k
        *data++ = value >> 56;
2190
2.02k
        value <<= 8;
2191
2.02k
    }
2192
341
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2193
341
    DEBUGIF("dumpv_send") {
2194
0
        char            i64buf[I64CHARSZ + 1];
2195
0
        printU64(i64buf, cp);
2196
0
        DEBUGMSG(("dumpv_send", "%s", i64buf));
2197
0
    }
2198
341
    return data;
2199
418
}
2200
2201
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2202
2203
2204
/**
2205
 * @internal
2206
 * asn_parse_signed_int64 - pulls a 64 bit signed long out of an ASN int
2207
 * type.
2208
 *
2209
 *  On entry, datalength is input as the number of valid bytes following
2210
 *   "data".  On exit, it is returned as the number of valid bytes
2211
 *   following the end of this object.
2212
 *
2213
 *  Returns a pointer to the first byte past the end
2214
 *   of this object (i.e. the start of the next object).
2215
 *  Returns NULL on any error.
2216
 
2217
 * @param data         IN - pointer to start of object
2218
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2219
 * @param type         OUT - asn type of object
2220
 * @param cp           IN/OUT - pointer to counter struct
2221
 * @param countersize  IN - size of output buffer
2222
 * @return  Returns a pointer to the first byte past the end
2223
 *          of this object (i.e. the start of the next object).
2224
 *          Returns NULL on any error.
2225
 */
2226
2227
u_char         *
2228
asn_parse_signed_int64(u_char * data,
2229
                       size_t * datalength,
2230
                       u_char * type,
2231
                       struct counter64 *cp, size_t countersize)
2232
3.00k
{
2233
3.00k
    static const char *errpre = "parse int64";
2234
3.00k
    const int       int64sizelimit = (4 * 2) + 1;
2235
3.00k
    char            ebuf[128];
2236
3.00k
    register u_char *bufp = data;
2237
3.00k
    u_long          asn_length;
2238
3.00k
    register u_int  low = 0, high = 0;
2239
2240
3.00k
    if (countersize != sizeof(struct counter64)) {
2241
0
        _asn_size_err(errpre, countersize, sizeof(struct counter64));
2242
0
        return NULL;
2243
0
    }
2244
2245
3.00k
    if (NULL == data || NULL == datalength || NULL == type || NULL == cp) {
2246
0
        ERROR_MSG("parse int64: NULL pointer");
2247
0
        return NULL;
2248
0
    }
2249
2250
    /** need at least 2 bytes to work with: type, length (which might be 0) */
2251
3.00k
    if (*datalength < 2) {
2252
0
        _asn_short_err(errpre, *datalength, 2);
2253
0
        return NULL;
2254
0
    }
2255
2256
3.00k
    *type = *bufp++;
2257
3.00k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2258
3.00k
    if (NULL == bufp) {
2259
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2260
0
        return NULL;
2261
0
    }
2262
2263
    /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_I64 */
2264
3.00k
    if (asn_length < 2) {
2265
38
        _asn_short_err(errpre, asn_length, 2);
2266
38
        return NULL;
2267
38
    }
2268
2269
2.97k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2270
2.97k
    if ((*type == ASN_OPAQUE) &&
2271
2.97k
        (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
2272
2.97k
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_I64)) {
2273
        /*
2274
         * change type to Int64 
2275
         */
2276
2.87k
        *type = *(bufp + 1);
2277
        /*
2278
         * value is encoded as special format 
2279
         */
2280
2.87k
        *datalength = asn_length;
2281
2.87k
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2282
2.87k
        if (NULL == bufp) {
2283
0
            _asn_short_err("parse opaque int64", *datalength - 2, asn_length);
2284
0
            return NULL;
2285
0
        }
2286
2.87k
    }
2287
    /*
2288
     * this should always have been true until snmp gets int64 PDU types 
2289
     */
2290
94
    else {
2291
94
        snprintf(ebuf, sizeof(ebuf),
2292
94
                "%s: wrong type: %d, len %d, buf bytes (%02X,%02X)",
2293
94
                errpre, *type, (int) asn_length, *bufp, *(bufp + 1));
2294
94
        ebuf[ sizeof(ebuf)-1 ] = 0;
2295
94
        ERROR_MSG(ebuf);
2296
94
        return NULL;
2297
94
    }
2298
2.87k
    if (((int) asn_length > int64sizelimit) ||
2299
2.87k
        (((int) asn_length == int64sizelimit) && *bufp != 0x00)) {
2300
17
        _asn_length_err(errpre, (size_t) asn_length, int64sizelimit);
2301
17
        return NULL;
2302
17
    }
2303
2.86k
    *datalength -= (int) asn_length + (bufp - data);
2304
2.86k
    if ((asn_length > 0) && (*bufp & 0x80)) {
2305
839
        low = 0xFFFFFFFFU;   /* first byte bit 1 means start the data with 1s */
2306
839
        high = 0xFFFFFF;
2307
839
    }
2308
2309
11.1k
    for ( ; asn_length; asn_length--) {
2310
8.29k
        high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
2311
8.29k
        low = ((low & 0x00FFFFFF) << 8) | *bufp++;
2312
8.29k
    }
2313
2314
2.86k
    CHECK_OVERFLOW_U(high,8);
2315
2.86k
    CHECK_OVERFLOW_U(low,8);
2316
2317
2.86k
    cp->low = low;
2318
2.86k
    cp->high = high;
2319
2320
2.86k
    DEBUGIF("dumpv_recv") {
2321
94
        char            i64buf[I64CHARSZ + 1];
2322
94
        printI64(i64buf, cp);
2323
94
        DEBUGMSG(("dumpv_recv", "Integer64: %s\n", i64buf));
2324
94
    }
2325
2326
2.86k
    return bufp;
2327
2.87k
}
2328
2329
2330
2331
/**
2332
 * @internal
2333
 * asn_build_signed_int64 - builds an ASN object containing a 64 bit integer.
2334
 *
2335
 *  On entry, datalength is input as the number of valid bytes following
2336
 *   "data".  On exit, it is returned as the number of valid bytes
2337
 *   following the end of this object.
2338
 *
2339
 *  Returns a pointer to the first byte past the end
2340
 *   of this object (i.e. the start of the next object).
2341
 *  Returns NULL on any error.
2342
 *
2343
 * @param data         IN - pointer to start of output buffer
2344
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2345
 * @param type         IN  - asn type of object
2346
 * @param cp           IN - pointer to counter struct
2347
 * @param countersize  IN - size of input buffer
2348
 * @return  Returns a pointer to the first byte past the end
2349
 *          of this object (i.e. the start of the next object).
2350
 *          Returns NULL on any error.
2351
 */
2352
u_char         *
2353
asn_build_signed_int64(u_char * data,
2354
                       size_t * datalength,
2355
                       u_char type,
2356
                       const struct counter64 *cp, size_t countersize)
2357
156
{
2358
    /*
2359
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
2360
     */
2361
2362
156
    register u_int  mask, mask2;
2363
156
    u_long          low;
2364
156
    long            high; /* MUST be signed because of CHECK_OVERFLOW_S(). */
2365
156
    size_t          intsize;
2366
156
    u_char         *initdatap = data;
2367
2368
156
    if (countersize != sizeof(struct counter64)) {
2369
0
        _asn_size_err("build int64", countersize,
2370
0
                      sizeof(struct counter64));
2371
0
        return NULL;
2372
0
    }
2373
156
    intsize = 8;
2374
156
    low = cp->low;
2375
156
    high = cp->high; /* unsigned to signed conversion */
2376
2377
156
    CHECK_OVERFLOW_S(high,9);
2378
156
    CHECK_OVERFLOW_U(low,9);
2379
2380
    /*
2381
     * Truncate "unnecessary" bytes off of the most significant end of this
2382
     * 2's complement integer.  There should be no sequence of 9
2383
     * consecutive 1's or 0's at the most significant end of the
2384
     * integer.
2385
     */
2386
156
    mask = 0xFF000000U;
2387
156
    mask2 = 0xFF800000U;
2388
692
    while ((((high & mask2) == 0) || ((high & mask2) == mask2))
2389
692
           && intsize > 1) {
2390
536
        intsize--;
2391
536
        high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
2392
536
        low = (low & 0x00ffffff) << 8;
2393
536
    }
2394
    /*
2395
     * until a real int64 gets incorperated into SNMP, we are going to
2396
     * encode it as an opaque instead.  First, we build the opaque
2397
     * header and then the int64 tag type we use to mark it as an
2398
     * int64 in the opaque string. 
2399
     */
2400
156
    data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2401
156
    if (_asn_build_header_check
2402
156
        ("build int64", data, *datalength, intsize + 3))
2403
24
        return NULL;
2404
2405
132
    *data++ = ASN_OPAQUE_TAG1;
2406
132
    *data++ = ASN_OPAQUE_I64;
2407
132
    *data++ = (u_char) intsize;
2408
132
    *datalength -= (3 + intsize);
2409
2410
689
    while (intsize--) {
2411
557
        *data++ = (u_char) (high >> 24);
2412
557
        high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
2413
557
        low = (low & 0x00ffffff) << 8;
2414
557
    }
2415
132
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2416
132
    DEBUGIF("dumpv_send") {
2417
0
        char            i64buf[I64CHARSZ + 1];
2418
0
        printU64(i64buf, cp);
2419
0
        DEBUGMSG(("dumpv_send", "%s\n", i64buf));
2420
0
    }
2421
132
    return data;
2422
156
}
2423
2424
2425
/**
2426
 * @internal
2427
 * asn_parse_float - pulls a single precision floating-point out of an opaque type.
2428
 *
2429
 *  On entry, datalength is input as the number of valid bytes following
2430
 *   "data".  On exit, it is returned as the number of valid bytes
2431
 *   following the end of this object.
2432
 *
2433
 *  Returns a pointer to the first byte past the end
2434
 *   of this object (i.e. the start of the next object).
2435
 *  Returns NULL on any error.
2436
 *
2437
 * @param data         IN - pointer to start of object
2438
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2439
 * @param type         OUT - asn type of object
2440
 * @param floatp       IN/OUT - pointer to float
2441
 * @param floatsize    IN - size of output buffer
2442
 * @return  Returns a pointer to the first byte past the end
2443
 *          of this object (i.e. the start of the next object).
2444
 *          Returns NULL on any error.
2445
 */
2446
u_char         *
2447
asn_parse_float(u_char * data,
2448
                size_t * datalength,
2449
                u_char * type, float *floatp, size_t floatsize)
2450
1.37k
{
2451
1.37k
    static const char *errpre = "parse float";
2452
1.37k
    register u_char *bufp = data;
2453
1.37k
    u_long          asn_length;
2454
1.37k
    union {
2455
1.37k
        float           floatVal;
2456
1.37k
        long            longVal;
2457
1.37k
        u_char          c[sizeof(float)];
2458
1.37k
    } fu;
2459
2460
1.37k
    if (floatsize != sizeof(float)) {
2461
0
        _asn_size_err("parse float", floatsize, sizeof(float));
2462
0
        return NULL;
2463
0
    }
2464
2465
1.37k
    if (NULL == data || NULL == datalength || NULL == type || NULL == floatp) {
2466
0
        ERROR_MSG("parse float: NULL pointer");
2467
0
        return NULL;
2468
0
    }
2469
2470
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
2471
1.37k
    if (*datalength < 2) {
2472
0
        _asn_short_err(errpre, *datalength, 2);
2473
0
        return NULL;
2474
0
    }
2475
2476
1.37k
    *type = *bufp++;
2477
1.37k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2478
1.37k
    if (NULL == bufp) {
2479
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2480
0
        return NULL;
2481
0
    }
2482
2483
1.37k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2484
    /*
2485
     * the float is encoded as an opaque 
2486
     */
2487
1.37k
    if ((*type == ASN_OPAQUE) &&
2488
1.37k
        (asn_length == ASN_OPAQUE_FLOAT_BER_LEN) &&
2489
1.37k
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_FLOAT)) {
2490
2491
        /*
2492
         * value is encoded as special format 
2493
         */
2494
419
        *datalength = asn_length;
2495
419
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2496
419
        if (NULL == bufp) {
2497
0
            _asn_short_err("parse opaque float", *datalength - 2, asn_length);
2498
0
            return NULL;
2499
0
        }
2500
        /*
2501
         * change type to Float 
2502
         */
2503
419
        *type = ASN_OPAQUE_FLOAT;
2504
419
    }
2505
2506
1.37k
    if (*type != ASN_OPAQUE_FLOAT) {
2507
21
        _asn_type_err(errpre, *type);
2508
21
        return NULL;
2509
21
    }
2510
2511
1.34k
    if (asn_length != sizeof(float)) {
2512
73
        _asn_size_err("parse seq float", asn_length, sizeof(float));
2513
73
        return NULL;
2514
73
    }
2515
2516
1.27k
    *datalength -= (int) asn_length + (bufp - data);
2517
1.27k
    memcpy(&fu.c[0], bufp, asn_length);
2518
2519
    /*
2520
     * correct for endian differences 
2521
     */
2522
1.27k
    fu.longVal = ntohl(fu.longVal);
2523
2524
1.27k
    *floatp = fu.floatVal;
2525
2526
1.27k
    DEBUGMSG(("dumpv_recv", "Opaque float: %f\n", *floatp));
2527
1.27k
    return bufp;
2528
1.34k
}
2529
2530
/**
2531
 * @internal
2532
 * asn_build_float - builds an ASN object containing a single precision floating-point
2533
 *                    number in an Opaque value.
2534
 *
2535
 *  On entry, datalength is input as the number of valid bytes following
2536
 *   "data".  On exit, it is returned as the number of valid bytes
2537
 *   following the end of this object.
2538
 *
2539
 *  Returns a pointer to the first byte past the end
2540
 *   of this object (i.e. the start of the next object).
2541
 *  Returns NULL on any error.
2542
 *
2543
 * @param data         IN - pointer to start of object
2544
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2545
 * @param type         IN - asn type of object
2546
 * @param floatp       IN - pointer to float
2547
 * @param floatsize    IN - size of input buffer
2548
 * @return  Returns a pointer to the first byte past the end
2549
 *          of this object (i.e. the start of the next object).
2550
 *          Returns NULL on any error.
2551
2552
 */
2553
u_char         *
2554
asn_build_float(u_char * data,
2555
                size_t * datalength,
2556
                u_char type, const float *floatp, size_t floatsize)
2557
64
{
2558
64
    union {
2559
64
        float           floatVal;
2560
64
        int             intVal;
2561
64
        u_char          c[sizeof(float)];
2562
64
    } fu;
2563
64
    u_char         *initdatap = data;
2564
2565
64
    if (floatsize != sizeof(float)) {
2566
0
        _asn_size_err("build float", floatsize, sizeof(float));
2567
0
        return NULL;
2568
0
    }
2569
    /*
2570
     * encode the float as an opaque 
2571
     */
2572
    /*
2573
     * turn into Opaque holding special tagged value 
2574
     */
2575
2576
    /*
2577
     * put the tag and length for the Opaque wrapper 
2578
     */
2579
64
    data = asn_build_header(data, datalength, ASN_OPAQUE, floatsize + 3);
2580
64
    if (_asn_build_header_check
2581
64
        ("build float", data, *datalength, (floatsize + 3)))
2582
15
        return NULL;
2583
2584
    /*
2585
     * put the special tag and length 
2586
     */
2587
49
    *data++ = ASN_OPAQUE_TAG1;
2588
49
    *data++ = ASN_OPAQUE_FLOAT;
2589
49
    *data++ = (u_char) floatsize;
2590
49
    *datalength = *datalength - 3;
2591
2592
49
    fu.floatVal = *floatp;
2593
    /*
2594
     * correct for endian differences 
2595
     */
2596
49
    fu.intVal = htonl(fu.intVal);
2597
2598
49
    *datalength -= floatsize;
2599
49
    memcpy(data, &fu.c[0], floatsize);
2600
2601
49
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2602
49
    DEBUGMSG(("dumpv_send", "Opaque float: %f\n", *floatp));
2603
49
    data += floatsize;
2604
49
    return data;
2605
64
}
2606
2607
2608
/**
2609
 * @internal
2610
 * asn_parse_double - pulls a double out of an opaque type.
2611
 *
2612
 *  On entry, datalength is input as the number of valid bytes following
2613
 *   "data".  On exit, it is returned as the number of valid bytes
2614
 *   following the end of this object.
2615
 *
2616
 *  Returns a pointer to the first byte past the end
2617
 *   of this object (i.e. the start of the next object).
2618
 *  Returns NULL on any error.
2619
 *
2620
 * @param data         IN - pointer to start of object
2621
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2622
 * @param type         OUT - asn type of object
2623
 * @param doublep       IN/OUT - pointer to double
2624
 * @param doublesize    IN - size of output buffer
2625
 * @return  Returns a pointer to the first byte past the end
2626
 *          of this object (i.e. the start of the next object).
2627
 *          Returns NULL on any error.
2628
 */
2629
u_char         *
2630
asn_parse_double(u_char * data,
2631
                 size_t * datalength,
2632
                 u_char * type, double *doublep, size_t doublesize)
2633
1.66k
{
2634
1.66k
    static const char *errpre = "parse double";
2635
1.66k
    register u_char *bufp = data;
2636
1.66k
    u_long          asn_length;
2637
1.66k
    long            tmp;
2638
1.66k
    union {
2639
1.66k
        double          doubleVal;
2640
1.66k
        int             intVal[2];
2641
1.66k
        u_char          c[sizeof(double)];
2642
1.66k
    } fu;
2643
2644
2645
1.66k
    if (doublesize != sizeof(double)) {
2646
0
        _asn_size_err("parse double", doublesize, sizeof(double));
2647
0
        return NULL;
2648
0
    }
2649
2650
1.66k
    if (NULL == data || NULL == datalength || NULL == type || NULL == doublep) {
2651
0
        ERROR_MSG("parse double: NULL pointer");
2652
0
        return NULL;
2653
0
    }
2654
2655
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
2656
1.66k
    if (*datalength < 2) {
2657
0
        _asn_short_err(errpre, *datalength, 2);
2658
0
        return NULL;
2659
0
    }
2660
2661
1.66k
    *type = *bufp++;
2662
1.66k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2663
1.66k
    if (NULL == bufp) {
2664
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2665
0
        return NULL;
2666
0
    }
2667
2668
1.66k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2669
    /*
2670
     * the double is encoded as an opaque 
2671
     */
2672
    /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_DOUBLE */
2673
1.66k
    if ((*type == ASN_OPAQUE) && (asn_length < 2)) {
2674
0
        _asn_short_err(errpre, asn_length, 2);
2675
0
        return NULL;
2676
0
    }
2677
1.66k
    if ((*type == ASN_OPAQUE) &&
2678
1.66k
        (asn_length == ASN_OPAQUE_DOUBLE_BER_LEN) &&
2679
1.66k
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_DOUBLE)) {
2680
2681
        /*
2682
         * value is encoded as special format 
2683
         */
2684
470
        *datalength = asn_length;
2685
470
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2686
470
        if (NULL == bufp) {
2687
0
            _asn_short_err("parse opaque double", *datalength - 2, asn_length);
2688
0
            return NULL;
2689
0
        }
2690
2691
        /*
2692
         * change type to Double 
2693
         */
2694
470
        *type = ASN_OPAQUE_DOUBLE;
2695
470
    }
2696
2697
1.66k
    if (*type != ASN_OPAQUE_DOUBLE) {
2698
64
        _asn_type_err(errpre, *type);
2699
64
        return NULL;
2700
64
    }
2701
2702
1.60k
    if (asn_length != sizeof(double)) {
2703
88
        _asn_size_err("parse seq double", asn_length, sizeof(double));
2704
88
        return NULL;
2705
88
    }
2706
1.51k
    *datalength -= (int) asn_length + (bufp - data);
2707
1.51k
    memcpy(&fu.c[0], bufp, asn_length);
2708
2709
    /*
2710
     * correct for endian differences 
2711
     */
2712
2713
1.51k
    tmp = ntohl(fu.intVal[0]);
2714
1.51k
    fu.intVal[0] = ntohl(fu.intVal[1]);
2715
1.51k
    fu.intVal[1] = tmp;
2716
2717
1.51k
    *doublep = fu.doubleVal;
2718
1.51k
    DEBUGMSG(("dumpv_recv", "  Opaque Double:\t%f\n", *doublep));
2719
2720
1.51k
    return bufp;
2721
1.60k
}
2722
2723
2724
/**
2725
 * @internal
2726
 * asn_build_double - builds an ASN object containing a double
2727
 *                    number in an Opaque value.
2728
 *
2729
 *  On entry, datalength is input as the number of valid bytes following
2730
 *   "data".  On exit, it is returned as the number of valid bytes
2731
 *   following the end of this object.
2732
 *
2733
 *  Returns a pointer to the first byte past the end
2734
 *   of this object (i.e. the start of the next object).
2735
 *  Returns NULL on any error.
2736
 *
2737
 * @param data         IN - pointer to start of object
2738
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2739
 * @param type         IN - asn type of object
2740
 * @param doublep      IN - pointer to double
2741
 * @param doublesize   IN - size of input buffer
2742
 * @return  Returns a pointer to the first byte past the end
2743
 *          of this object (i.e. the start of the next object).
2744
 *          Returns NULL on any error.
2745
 */
2746
u_char         *
2747
asn_build_double(u_char * data,
2748
                 size_t * datalength,
2749
                 u_char type, const double *doublep, size_t doublesize)
2750
41
{
2751
41
    long            tmp;
2752
41
    union {
2753
41
        double          doubleVal;
2754
41
        int             intVal[2];
2755
41
        u_char          c[sizeof(double)];
2756
41
    } fu;
2757
41
    u_char         *initdatap = data;
2758
2759
41
    if (doublesize != sizeof(double)) {
2760
0
        _asn_size_err("build double", doublesize, sizeof(double));
2761
0
        return NULL;
2762
0
    }
2763
2764
    /*
2765
     * encode the double as an opaque 
2766
     */
2767
    /*
2768
     * turn into Opaque holding special tagged value 
2769
     */
2770
2771
    /*
2772
     * put the tag and length for the Opaque wrapper 
2773
     */
2774
41
    data = asn_build_header(data, datalength, ASN_OPAQUE, doublesize + 3);
2775
41
    if (_asn_build_header_check
2776
41
        ("build double", data, *datalength, doublesize + 3))
2777
6
        return NULL;
2778
2779
    /*
2780
     * put the special tag and length 
2781
     */
2782
35
    *data++ = ASN_OPAQUE_TAG1;
2783
35
    *data++ = ASN_OPAQUE_DOUBLE;
2784
35
    *data++ = (u_char) doublesize;
2785
35
    *datalength = *datalength - 3;
2786
2787
35
    fu.doubleVal = *doublep;
2788
    /*
2789
     * correct for endian differences 
2790
     */
2791
35
    tmp = htonl(fu.intVal[0]);
2792
35
    fu.intVal[0] = htonl(fu.intVal[1]);
2793
35
    fu.intVal[1] = tmp;
2794
35
    *datalength -= doublesize;
2795
35
    memcpy(data, &fu.c[0], doublesize);
2796
2797
35
    data += doublesize;
2798
35
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2799
35
    DEBUGMSG(("dumpv_send", "  Opaque double: %f\n", *doublep));
2800
35
    return data;
2801
41
}
2802
2803
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2804
2805
2806
/**
2807
 * @internal
2808
 * This function increases the size of the buffer pointed to by *pkt, which
2809
 * is initially of size *pkt_len.  Contents are preserved **AT THE TOP END OF 
2810
 * THE BUFFER** (hence making this function useful for reverse encoding).
2811
 * You can change the reallocation scheme, but you **MUST** guarantee to
2812
 * allocate **AT LEAST** one extra byte.  If memory cannot be reallocated,
2813
 * then return 0; otherwise return 1.   
2814
 * 
2815
 * @param pkt     buffer to increase
2816
 * @param pkt_len initial buffer size
2817
 * 
2818
 * @return 1 on success 0 on error (memory cannot be reallocated)
2819
 */
2820
int
2821
asn_realloc(u_char ** pkt, size_t * pkt_len)
2822
0
{
2823
0
    if (pkt != NULL && pkt_len != NULL) {
2824
0
        size_t          old_pkt_len = *pkt_len;
2825
2826
0
        DEBUGMSGTL(("asn_realloc", " old_pkt %8p, old_pkt_len %" NETSNMP_PRIz
2827
0
                    "u\n", *pkt, old_pkt_len));
2828
2829
0
        if (snmp_realloc(pkt, pkt_len)) {
2830
0
            DEBUGMSGTL(("asn_realloc", " new_pkt %8p, new_pkt_len %"
2831
0
                        NETSNMP_PRIz "u\n", *pkt, *pkt_len));
2832
0
            DEBUGMSGTL(("asn_realloc", " memmove(%8p + %08" NETSNMP_PRIz
2833
0
                        "x, %8p, %08" NETSNMP_PRIz "x)\n", *pkt,
2834
0
                        *pkt_len - old_pkt_len, *pkt, old_pkt_len));
2835
0
            memmove(*pkt + (*pkt_len - old_pkt_len), *pkt, old_pkt_len);
2836
0
            memset(*pkt, ' ', *pkt_len - old_pkt_len);
2837
0
            return 1;
2838
0
        } else {
2839
0
            DEBUGMSG(("asn_realloc", " CANNOT REALLOC()\n"));
2840
0
        }
2841
0
    }
2842
0
    return 0;
2843
0
}
2844
2845
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2846
2847
/**
2848
 * @internal
2849
 * reverse  builds an ASN header for a length with
2850
 * length specified.
2851
 * 
2852
 * @param pkt     IN/OUT address of the begining of the buffer.
2853
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
2854
 * @param offset  IN/OUT offset to the start of the buffer where to write
2855
 * @param r       IN if not zero reallocate the buffer to fit the 
2856
 *                needed size.
2857
 * @param length  IN - length of object
2858
 *
2859
 * @return 1 on success, 0 on error
2860
 */
2861
int
2862
asn_realloc_rbuild_length(u_char ** pkt, size_t * pkt_len,
2863
                          size_t * offset, int r, size_t length)
2864
7.50k
{
2865
7.50k
    static const char *errpre = "build length";
2866
7.50k
    char            ebuf[128];
2867
7.50k
    int             tmp_int;
2868
7.50k
    size_t          start_offset = *offset;
2869
2870
7.50k
    if (length <= 0x7f) {
2871
7.46k
        if (((*pkt_len - *offset) < 1)
2872
7.46k
            && !(r && asn_realloc(pkt, pkt_len))) {
2873
0
            snprintf(ebuf, sizeof(ebuf),
2874
0
                    "%s: bad length < 1 :%ld, %lu", errpre,
2875
0
                    (long)(*pkt_len - *offset), (unsigned long)length);
2876
0
            ebuf[ sizeof(ebuf)-1 ] = 0;
2877
0
            ERROR_MSG(ebuf);
2878
0
            return 0;
2879
0
        }
2880
7.46k
        *(*pkt + *pkt_len - (++*offset)) = length;
2881
7.46k
    } else {
2882
37
        while (length > 0xff) {
2883
0
            if (((*pkt_len - *offset) < 1)
2884
0
                && !(r && asn_realloc(pkt, pkt_len))) {
2885
0
                snprintf(ebuf, sizeof(ebuf),
2886
0
                        "%s: bad length < 1 :%ld, %lu", errpre,
2887
0
                        (long)(*pkt_len - *offset), (unsigned long)length);
2888
0
                ebuf[ sizeof(ebuf)-1 ] = 0;
2889
0
                ERROR_MSG(ebuf);
2890
0
                return 0;
2891
0
            }
2892
0
            *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
2893
0
            length >>= 8;
2894
0
        }
2895
2896
37
        while ((*pkt_len - *offset) < 2) {
2897
0
            if (!(r && asn_realloc(pkt, pkt_len))) {
2898
0
                snprintf(ebuf, sizeof(ebuf),
2899
0
                        "%s: bad length < 1 :%ld, %lu", errpre,
2900
0
                        (long)(*pkt_len - *offset), (unsigned long)length);
2901
0
                ebuf[ sizeof(ebuf)-1 ] = 0;
2902
0
                ERROR_MSG(ebuf);
2903
0
                return 0;
2904
0
            }
2905
0
        }
2906
2907
37
        *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
2908
37
        tmp_int = *offset - start_offset;
2909
37
        *(*pkt + *pkt_len - (++*offset)) = tmp_int | 0x80;
2910
37
    }
2911
2912
7.50k
    return 1;
2913
7.50k
}
2914
2915
/**
2916
 * @internal
2917
 * builds an ASN header for an object with the ID and
2918
 * length specified.
2919
 *
2920
 * @see asn_build_header
2921
 * 
2922
 * @param pkt     IN/OUT address of the begining of the buffer.
2923
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
2924
 * @param offset  IN/OUT offset to the start of the buffer where to write
2925
 * @param r       IN if not zero reallocate the buffer to fit the 
2926
 *                needed size.
2927
 * @param type   IN - type of object
2928
 * @param length   IN - length of object
2929
 *
2930
 * @return 1 on success, 0 on error
2931
 */
2932
int
2933
asn_realloc_rbuild_header(u_char ** pkt, size_t * pkt_len,
2934
                          size_t * offset, int r,
2935
                          u_char type, size_t length)
2936
7.50k
{
2937
7.50k
    char            ebuf[128];
2938
2939
7.50k
    if (asn_realloc_rbuild_length(pkt, pkt_len, offset, r, length)) {
2940
7.50k
        if (((*pkt_len - *offset) < 1)
2941
7.50k
            && !(r && asn_realloc(pkt, pkt_len))) {
2942
0
            snprintf(ebuf, sizeof(ebuf),
2943
0
                    "bad header length < 1 :%ld, %lu",
2944
0
                    (long)(*pkt_len - *offset), (unsigned long)length);
2945
0
            ebuf[ sizeof(ebuf)-1 ] = 0;
2946
0
            ERROR_MSG(ebuf);
2947
0
            return 0;
2948
0
        }
2949
7.50k
        *(*pkt + *pkt_len - (++*offset)) = type;
2950
7.50k
        return 1;
2951
7.50k
    }
2952
0
    return 0;
2953
7.50k
}
2954
2955
/**
2956
 * @internal
2957
 * builds an ASN object containing an int.
2958
 *
2959
 * @see asn_build_int
2960
 * 
2961
 * @param pkt     IN/OUT address of the begining of the buffer.
2962
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
2963
 * @param offset  IN/OUT offset to the start of the buffer where to write
2964
 * @param r       IN if not zero reallocate the buffer to fit the 
2965
 *                needed size.
2966
 * @param type    IN - type of object
2967
 * @param intp    IN - pointer to start of long integer
2968
 * @param intsize IN - size of input buffer
2969
 *
2970
 * @return 1 on success, 0 on error
2971
 */
2972
int
2973
asn_realloc_rbuild_int(u_char ** pkt, size_t * pkt_len,
2974
                       size_t * offset, int r,
2975
                       u_char type, const long *intp, size_t intsize)
2976
1.84k
{
2977
1.84k
    static const char *errpre = "build int";
2978
1.84k
    register long   integer = *intp;
2979
1.84k
    int             testvalue;
2980
1.84k
    size_t          start_offset = *offset;
2981
2982
1.84k
    if (intsize != sizeof(long)) {
2983
0
        _asn_size_err(errpre, intsize, sizeof(long));
2984
0
        return 0;
2985
0
    }
2986
2987
1.84k
    CHECK_OVERFLOW_S(integer,10);
2988
1.84k
    testvalue = (integer < 0) ? -1 : 0;
2989
2990
1.84k
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
2991
0
        return 0;
2992
0
    }
2993
1.84k
    *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
2994
1.84k
    integer >>= 8;
2995
2996
3.82k
    while (integer != testvalue) {
2997
1.98k
        if (((*pkt_len - *offset) < 1)
2998
1.98k
            && !(r && asn_realloc(pkt, pkt_len))) {
2999
0
            return 0;
3000
0
        }
3001
1.98k
        *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3002
1.98k
        integer >>= 8;
3003
1.98k
    }
3004
3005
1.84k
    if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) {
3006
        /*
3007
         * Make sure left most bit is representational of the rest of the bits
3008
         * that aren't encoded.  
3009
         */
3010
234
        if (((*pkt_len - *offset) < 1)
3011
234
            && !(r && asn_realloc(pkt, pkt_len))) {
3012
0
            return 0;
3013
0
        }
3014
234
        *(*pkt + *pkt_len - (++*offset)) = testvalue & 0xff;
3015
234
    }
3016
3017
1.84k
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3018
1.84k
                                  (*offset - start_offset))) {
3019
1.84k
        if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
3020
1.84k
                                            (*offset - start_offset))) {
3021
0
            return 0;
3022
1.84k
        } else {
3023
1.84k
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3024
1.84k
                           (*offset - start_offset));
3025
1.84k
            DEBUGMSG(("dumpv_send", "  Integer:\t%ld (0x%.2lX)\n", *intp,
3026
1.84k
                      *intp));
3027
1.84k
            return 1;
3028
1.84k
        }
3029
1.84k
    }
3030
3031
0
    return 0;
3032
1.84k
}
3033
3034
/**
3035
 * @internal
3036
 * builds an ASN object containing an string.
3037
 *
3038
 * @see asn_build_string 
3039
 * 
3040
 * @param pkt     IN/OUT address of the begining of the buffer.
3041
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3042
 * @param offset  IN/OUT offset to the start of the buffer where to write
3043
 * @param r       IN if not zero reallocate the buffer to fit the 
3044
 *                needed size.
3045
 * @param type    IN - type of object
3046
 * @param string    IN - pointer to start of the string
3047
 * @param strlength IN - size of input buffer
3048
 *
3049
 * @return 1 on success, 0 on error
3050
 */
3051
3052
int
3053
asn_realloc_rbuild_string(u_char ** pkt, size_t * pkt_len,
3054
                          size_t * offset, int r,
3055
                          u_char type,
3056
                          const u_char * str, size_t strlength)
3057
568
{
3058
568
    static const char *errpre = "build string";
3059
568
    size_t          start_offset = *offset;
3060
3061
568
    while ((*pkt_len - *offset) < strlength) {
3062
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3063
0
            return 0;
3064
0
        }
3065
0
    }
3066
3067
568
    *offset += strlength;
3068
568
    if (str)
3069
568
        memcpy(*pkt + *pkt_len - *offset, str, strlength);
3070
3071
568
    if (asn_realloc_rbuild_header
3072
568
        (pkt, pkt_len, offset, r, type, strlength)) {
3073
568
        if (_asn_realloc_build_header_check
3074
568
            (errpre, pkt, pkt_len, strlength)) {
3075
0
            return 0;
3076
568
        } else {
3077
568
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3078
568
                           *offset - start_offset);
3079
568
            DEBUGIF("dumpv_send") {
3080
0
                if (strlength == 0) {
3081
0
                    DEBUGMSG(("dumpv_send", "  String: [NULL]\n"));
3082
0
                } else {
3083
0
                    u_char         *buf = (u_char *) malloc(2 * strlength);
3084
0
                    size_t          l =
3085
0
                        (buf != NULL) ? (2 * strlength) : 0, ol = 0;
3086
3087
0
                    if (sprint_realloc_asciistring
3088
0
                        (&buf, &l, &ol, 1, str, strlength)) {
3089
0
                        DEBUGMSG(("dumpv_send", "  String:\t%s\n", buf));
3090
0
                    } else {
3091
0
                        if (buf == NULL) {
3092
0
                            DEBUGMSG(("dumpv_send",
3093
0
                                      "  String:\t[TRUNCATED]\n"));
3094
0
                        } else {
3095
0
                            DEBUGMSG(("dumpv_send",
3096
0
                                      "  String:\t%s [TRUNCATED]\n", buf));
3097
0
                        }
3098
0
                    }
3099
0
                    if (buf != NULL) {
3100
0
                        free(buf);
3101
0
                    }
3102
0
                }
3103
0
            }
3104
568
        }
3105
568
        return 1;
3106
568
    }
3107
3108
0
    return 0;
3109
568
}
3110
3111
/**
3112
 * @internal
3113
 * builds an ASN object containing an unsigned int.
3114
 *
3115
 * @see asn_build_unsigned_int
3116
 * 
3117
 * @param pkt     IN/OUT address of the begining of the buffer.
3118
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3119
 * @param offset  IN/OUT offset to the start of the buffer where to write
3120
 * @param r       IN if not zero reallocate the buffer to fit the 
3121
 *                needed size.
3122
 * @param type    IN - type of object
3123
 * @param intp    IN - pointer to start of unsigned int
3124
 * @param intsize IN - size of input buffer
3125
 *
3126
 * @return 1 on success, 0 on error
3127
 */
3128
int
3129
asn_realloc_rbuild_unsigned_int(u_char ** pkt, size_t * pkt_len,
3130
                                size_t * offset, int r,
3131
                            u_char type, const u_long * intp, size_t intsize)
3132
248
{
3133
248
    static const char *errpre = "build uint";
3134
248
    register u_long integer = *intp;
3135
248
    size_t          start_offset = *offset;
3136
3137
248
    if (intsize != sizeof(unsigned long)) {
3138
0
        _asn_size_err(errpre, intsize, sizeof(unsigned long));
3139
0
        return 0;
3140
0
    }
3141
3142
248
    CHECK_OVERFLOW_U(integer,11);
3143
3144
248
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3145
0
        return 0;
3146
0
    }
3147
248
    *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3148
248
    integer >>= 8;
3149
3150
710
    while (integer != 0) {
3151
462
        if (((*pkt_len - *offset) < 1)
3152
462
            && !(r && asn_realloc(pkt, pkt_len))) {
3153
0
            return 0;
3154
0
        }
3155
462
        *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3156
462
        integer >>= 8;
3157
462
    }
3158
3159
248
    if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
3160
        /*
3161
         * Make sure left most bit is representational of the rest of the bits
3162
         * that aren't encoded.  
3163
         */
3164
157
        if (((*pkt_len - *offset) < 1)
3165
157
            && !(r && asn_realloc(pkt, pkt_len))) {
3166
0
            return 0;
3167
0
        }
3168
157
        *(*pkt + *pkt_len - (++*offset)) = 0;
3169
157
    }
3170
3171
248
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3172
248
                                  (*offset - start_offset))) {
3173
248
        if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
3174
248
                                            (*offset - start_offset))) {
3175
0
            return 0;
3176
248
        } else {
3177
248
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3178
248
                           (*offset - start_offset));
3179
248
            DEBUGMSG(("dumpv_send", "  UInteger:\t%lu (0x%.2lX)\n", *intp,
3180
248
                      *intp));
3181
248
            return 1;
3182
248
        }
3183
248
    }
3184
3185
0
    return 0;
3186
248
}
3187
3188
/**
3189
 * @internal
3190
 * builds an ASN object containing an sequence.
3191
 *
3192
 * @see asn_build_sequence
3193
 * 
3194
 * @param pkt     IN/OUT address of the begining of the buffer.
3195
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3196
 * @param offset  IN/OUT offset to the start of the buffer where to write
3197
 * @param r       IN if not zero reallocate the buffer to fit the 
3198
 *                needed size.
3199
 * @param type    IN - type of object
3200
 * @param length IN - length of object
3201
 *
3202
 * @return 1 on success, 0 on error
3203
 */
3204
3205
int
3206
asn_realloc_rbuild_sequence(u_char ** pkt, size_t * pkt_len,
3207
                            size_t * offset, int r,
3208
                            u_char type, size_t length)
3209
2.64k
{
3210
2.64k
    return asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3211
2.64k
                                     length);
3212
2.64k
}
3213
3214
/**
3215
 * @internal
3216
 * Store a single byte while reverse encoding.
3217
 * @param pkt[in|out]     Start of the buffer.
3218
 * @param pkt_len[in|out] Size of the buffer in bytes.
3219
 * @param offset[in|out]  Offset from the end of the buffer where to write.
3220
 * @param r[in]           If not zero, increase the buffer size if needed.
3221
 * @param byte[in]        Data to store.
3222
 *
3223
 * @return 1 on success, 0 on error.
3224
 */
3225
static int store_byte(uint8_t **pkt, size_t *pkt_len, size_t *offset, int r,
3226
                      uint8_t byte)
3227
5.97k
{
3228
5.97k
    netsnmp_assert(*offset <= *pkt_len);
3229
5.97k
    if (*offset >= *pkt_len && (!r || !asn_realloc(pkt, pkt_len)))
3230
0
        return 0;
3231
5.97k
    netsnmp_assert(*offset < *pkt_len);
3232
5.97k
    *(*pkt + *pkt_len - (++*offset)) = byte;
3233
5.97k
    return 1;
3234
5.97k
}
3235
3236
/**
3237
 * @internal
3238
 * Store 32 bits while reverse encoding.
3239
 * @param pkt[in|out]     Start of the buffer.
3240
 * @param pkt_len[in|out] Size of the buffer in bytes.
3241
 * @param offset[in|out]  Offset from the end of the buffer where to write.
3242
 * @param r[in]           If not zero, increase the buffer size if needed.
3243
 * @param subid[in]       Data to store.
3244
 *
3245
 * @return 1 on success, 0 on error.
3246
 */
3247
static int store_uint32(uint8_t **pkt, size_t *pkt_len, size_t *offset, int r,
3248
                        uint32_t subid)
3249
4.43k
{
3250
4.43k
    if (!store_byte(pkt, pkt_len, offset, r, subid & 0x7f))
3251
0
        return 0;
3252
3253
5.97k
    for (subid >>= 7; subid; subid >>= 7)
3254
1.54k
        if (!store_byte(pkt, pkt_len, offset, r, subid | 0x80))
3255
0
            return 0;
3256
3257
4.43k
    return 1;
3258
4.43k
}
3259
3260
/**
3261
 * @internal
3262
 * builds an ASN object containing an objid.
3263
 *
3264
 * @see asn_build_objid
3265
 * 
3266
 * @param pkt     IN/OUT address of the begining of the buffer.
3267
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3268
 * @param offset  IN/OUT offset to the start of the buffer where to write
3269
 * @param r       IN if not zero reallocate the buffer to fit the 
3270
 *                needed size.
3271
 * @param type    IN - type of object
3272
 * @param objid   IN - pointer to the object id
3273
 * @param objidlength  IN - length of the input 
3274
 *
3275
 * @return 1 on success, 0 on error
3276
 */
3277
3278
int
3279
asn_realloc_rbuild_objid(u_char ** pkt, size_t * pkt_len,
3280
                         size_t * offset, int r,
3281
                         u_char type,
3282
                         const oid * objid, size_t objidlength)
3283
1.43k
{
3284
    /*
3285
     * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
3286
     * subidentifier ::= {leadingbyte}* lastbyte
3287
     * leadingbyte ::= 1 7bitvalue
3288
     * lastbyte ::= 0 7bitvalue
3289
     */
3290
1.43k
    register size_t i;
3291
1.43k
    register oid    tmpint;
3292
1.43k
    size_t          start_offset = *offset;
3293
1.43k
    const char     *errpre = "build objid";
3294
3295
    /*
3296
     * Check if there are at least 2 sub-identifiers.  
3297
     */
3298
1.43k
    if (objidlength == 0) {
3299
        /*
3300
         * There are not, so make the OID have two sub-identifiers with value
3301
         * zero. Encode both sub-identifiers as a single byte.
3302
         */
3303
0
        if (!store_byte(pkt, pkt_len, offset, r, 0))
3304
0
            return 0;
3305
1.43k
    } else if (objid[0] > 2) {
3306
0
        ERROR_MSG("build objid: bad first subidentifier");
3307
0
        return 0;
3308
1.43k
    } else if (objidlength == 1) {
3309
        /*
3310
         * Encode the first value.  
3311
         */
3312
0
        if (!store_byte(pkt, pkt_len, offset, r, 40 * objid[0]))
3313
0
            return 0;
3314
1.43k
    } else {
3315
4.43k
        for (i = objidlength - 1; i >= 2; i--) {
3316
2.99k
            tmpint = objid[i];
3317
2.99k
            CHECK_OVERFLOW_U(tmpint, 12);
3318
2.99k
            if (!store_uint32(pkt, pkt_len, offset, r, tmpint))
3319
0
                return 0;
3320
2.99k
        }
3321
3322
        /*
3323
         * Combine the first two values.  
3324
         */
3325
1.43k
        if (objid[1] > 40 && objid[0] < 2) {
3326
0
            ERROR_MSG("build objid: bad second subidentifier");
3327
0
            return 0;
3328
0
        }
3329
1.43k
        if (!store_uint32(pkt, pkt_len, offset, r, objid[0] * 40 + objid[1]))
3330
0
            return 0;
3331
1.43k
    }
3332
3333
1.43k
    tmpint = *offset - start_offset;
3334
1.43k
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, tmpint)) {
3335
1.43k
        if (_asn_realloc_build_header_check(errpre, pkt, pkt_len, tmpint)) {
3336
0
            return 0;
3337
1.43k
        } else {
3338
1.43k
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), tmpint);
3339
1.43k
            DEBUGMSG(("dumpv_send", "  ObjID: "));
3340
1.43k
            DEBUGMSGOID(("dumpv_send", objid, objidlength));
3341
1.43k
            DEBUGMSG(("dumpv_send", "\n"));
3342
1.43k
            return 1;
3343
1.43k
        }
3344
1.43k
    }
3345
3346
0
    return 0;
3347
1.43k
}
3348
3349
/**
3350
 * @internal
3351
 * builds an ASN object containing an null object.
3352
 *
3353
 * @see asn_build_null
3354
 * 
3355
 * @param pkt     IN/OUT address of the begining of the buffer.
3356
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3357
 * @param offset  IN/OUT offset to the start of the buffer where to write
3358
 * @param r       IN if not zero reallocate the buffer to fit the 
3359
 *                needed size.
3360
 * @param type    IN - type of object
3361
 *
3362
 * @return 1 on success, 0 on error
3363
 */
3364
3365
int
3366
asn_realloc_rbuild_null(u_char ** pkt, size_t * pkt_len,
3367
                        size_t * offset, int r, u_char type)
3368
140
{
3369
    /*
3370
     * ASN.1 null ::= 0x05 0x00
3371
     */
3372
140
    size_t          start_offset = *offset;
3373
3374
140
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 0)) {
3375
140
        DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3376
140
                       (*offset - start_offset));
3377
140
        DEBUGMSG(("dumpv_send", "  NULL\n"));
3378
140
        return 1;
3379
140
    } else {
3380
0
        return 0;
3381
0
    }
3382
140
}
3383
3384
/**
3385
 * @internal
3386
 * builds an ASN object containing an bitstring.
3387
 *
3388
 * @see asn_build_bitstring
3389
 * 
3390
 * @param pkt     IN/OUT address of the begining of the buffer.
3391
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3392
 * @param offset  IN/OUT offset to the start of the buffer where to write
3393
 * @param r       IN if not zero reallocate the buffer to fit the 
3394
 *                needed size.
3395
 * @param type    IN - type of object
3396
 * @param string   IN - pointer to the string
3397
 * @param strlength  IN - length of the input 
3398
 *
3399
 * @return 1 on success, 0 on error
3400
 */
3401
3402
int
3403
asn_realloc_rbuild_bitstring(u_char ** pkt, size_t * pkt_len,
3404
                             size_t * offset, int r,
3405
                             u_char type,
3406
                             const u_char * str, size_t strlength)
3407
47
{
3408
    /*
3409
     * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
3410
     */
3411
47
    static const char *errpre = "build bitstring";
3412
47
    size_t          start_offset = *offset;
3413
3414
47
    while ((*pkt_len - *offset) < strlength) {
3415
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3416
0
            return 0;
3417
0
        }
3418
0
    }
3419
3420
47
    *offset += strlength;
3421
47
    memcpy(*pkt + *pkt_len - *offset, str, strlength);
3422
3423
47
    if (asn_realloc_rbuild_header
3424
47
        (pkt, pkt_len, offset, r, type, strlength)) {
3425
47
        if (_asn_realloc_build_header_check
3426
47
            (errpre, pkt, pkt_len, strlength)) {
3427
0
            return 0;
3428
47
        } else {
3429
47
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3430
47
                           *offset - start_offset);
3431
47
            DEBUGIF("dumpv_send") {
3432
0
                if (strlength == 0) {
3433
0
                    DEBUGMSG(("dumpv_send", "  Bitstring: [NULL]\n"));
3434
0
                } else {
3435
0
                    u_char         *buf = (u_char *) malloc(2 * strlength);
3436
0
                    size_t          l =
3437
0
                        (buf != NULL) ? (2 * strlength) : 0, ol = 0;
3438
3439
0
                    if (sprint_realloc_asciistring
3440
0
                        (&buf, &l, &ol, 1, str, strlength)) {
3441
0
                        DEBUGMSG(("dumpv_send", "  Bitstring:\t%s\n",
3442
0
                                  buf));
3443
0
                    } else {
3444
0
                        if (buf == NULL) {
3445
0
                            DEBUGMSG(("dumpv_send",
3446
0
                                      "  Bitstring:\t[TRUNCATED]\n"));
3447
0
                        } else {
3448
0
                            DEBUGMSG(("dumpv_send",
3449
0
                                      "  Bitstring:\t%s [TRUNCATED]\n",
3450
0
                                      buf));
3451
0
                        }
3452
0
                    }
3453
0
                    if (buf != NULL) {
3454
0
                        free(buf);
3455
0
                    }
3456
0
                }
3457
0
            }
3458
47
        }
3459
47
        return 1;
3460
47
    }
3461
3462
0
    return 0;
3463
47
}
3464
3465
/**
3466
 * @internal
3467
 * builds an ASN object containing an unsigned int64.
3468
 *
3469
 * @see asn_build_unsigned_int64
3470
 * 
3471
 * @param pkt     IN/OUT address of the begining of the buffer.
3472
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3473
 * @param offset  IN/OUT offset to the start of the buffer where to write
3474
 * @param r       IN if not zero reallocate the buffer to fit the 
3475
 *                needed size.
3476
 * @param type    IN - type of object
3477
 * @param cp           IN - pointer to counter struct
3478
 * @param countersize  IN - size of input buffer
3479
 *
3480
 * @return 1 on success, 0 on error
3481
 */
3482
int
3483
asn_realloc_rbuild_unsigned_int64(u_char ** pkt, size_t * pkt_len,
3484
                                  size_t * offset, int r,
3485
                                  u_char type,
3486
                               const struct counter64 *cp, size_t countersize)
3487
293
{
3488
    /*
3489
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
3490
     */
3491
293
    register u_long low = cp->low, high = cp->high;
3492
293
    size_t          intsize, start_offset = *offset;
3493
293
    int             count;
3494
3495
293
    if (countersize != sizeof(struct counter64)) {
3496
0
        _asn_size_err("build uint64", countersize,
3497
0
                      sizeof(struct counter64));
3498
0
        return 0;
3499
0
    }
3500
3501
293
    CHECK_OVERFLOW_U(high,13);
3502
293
    CHECK_OVERFLOW_U(low,13);
3503
3504
    /*
3505
     * Encode the low 4 bytes first.  
3506
     */
3507
293
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3508
0
        return 0;
3509
0
    }
3510
293
    *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3511
293
    low >>= 8;
3512
293
    count = 1;
3513
3514
899
    while (low != 0) {
3515
606
        count++;
3516
606
        if (((*pkt_len - *offset) < 1)
3517
606
            && !(r && asn_realloc(pkt, pkt_len))) {
3518
0
            return 0;
3519
0
        }
3520
606
        *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3521
606
        low >>= 8;
3522
606
    }
3523
3524
    /*
3525
     * Then the high byte if present.  
3526
     */
3527
293
    if (high) {
3528
        /*
3529
         * Do the rest of the low byte.  
3530
         */
3531
176
        for (; count < 4; count++) {
3532
0
            if (((*pkt_len - *offset) < 1)
3533
0
                && !(r && asn_realloc(pkt, pkt_len))) {
3534
0
                return 0;
3535
0
            }
3536
0
            *(*pkt + *pkt_len - (++*offset)) = 0;
3537
0
        }
3538
3539
        /*
3540
         * Do high byte.  
3541
         */
3542
176
        if (((*pkt_len - *offset) < 1)
3543
176
            && !(r && asn_realloc(pkt, pkt_len))) {
3544
0
            return 0;
3545
0
        }
3546
176
        *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3547
176
        high >>= 8;
3548
3549
536
        while (high != 0) {
3550
360
            if (((*pkt_len - *offset) < 1)
3551
360
                && !(r && asn_realloc(pkt, pkt_len))) {
3552
0
                return 0;
3553
0
            }
3554
360
            *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3555
360
            high >>= 8;
3556
360
        }
3557
176
    }
3558
3559
293
    if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
3560
        /*
3561
         * Make sure left most bit is representational of the rest of the bits
3562
         * that aren't encoded.  
3563
         */
3564
214
        if (((*pkt_len - *offset) < 1)
3565
214
            && !(r && asn_realloc(pkt, pkt_len))) {
3566
0
            return 0;
3567
0
        }
3568
214
        *(*pkt + *pkt_len - (++*offset)) = 0;
3569
214
    }
3570
3571
293
    intsize = *offset - start_offset;
3572
3573
293
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3574
    /*
3575
     * Encode a Counter64 as an opaque (it also works in SNMPv1).  
3576
     */
3577
293
    if (type == ASN_OPAQUE_COUNTER64) {
3578
35
        while ((*pkt_len - *offset) < 5) {
3579
0
            if (!(r && asn_realloc(pkt, pkt_len))) {
3580
0
                return 0;
3581
0
            }
3582
0
        }
3583
3584
35
        *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3585
35
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_COUNTER64;
3586
35
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3587
3588
        /*
3589
         * Put the tag and length for the Opaque wrapper.  
3590
         */
3591
35
        if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3592
35
                                      ASN_OPAQUE, intsize + 3)) {
3593
35
            if (_asn_realloc_build_header_check
3594
35
                ("build counter u64", pkt, pkt_len, intsize + 3)) {
3595
0
                return 0;
3596
0
            }
3597
35
        } else {
3598
0
            return 0;
3599
0
        }
3600
258
    } else if (type == ASN_OPAQUE_U64) {
3601
        /*
3602
         * Encode the Unsigned int64 in an opaque.  
3603
         */
3604
68
        while ((*pkt_len - *offset) < 5) {
3605
0
            if (!(r && asn_realloc(pkt, pkt_len))) {
3606
0
                return 0;
3607
0
            }
3608
0
        }
3609
3610
68
        *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3611
68
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_U64;
3612
68
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3613
3614
        /*
3615
         * Put the tag and length for the Opaque wrapper.  
3616
         */
3617
68
        if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3618
68
                                      ASN_OPAQUE, intsize + 3)) {
3619
68
            if (_asn_realloc_build_header_check
3620
68
                ("build counter u64", pkt, pkt_len, intsize + 3)) {
3621
0
                return 0;
3622
0
            }
3623
68
        } else {
3624
0
            return 0;
3625
0
        }
3626
190
    } else {
3627
3628
190
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3629
190
        if (asn_realloc_rbuild_header
3630
190
            (pkt, pkt_len, offset, r, type, intsize)) {
3631
190
            if (_asn_realloc_build_header_check
3632
190
                ("build uint64", pkt, pkt_len, intsize)) {
3633
0
                return 0;
3634
0
            }
3635
190
        } else {
3636
0
            return 0;
3637
0
        }
3638
190
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3639
190
    }
3640
293
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3641
3642
293
    DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
3643
293
    DEBUGMSG(("dumpv_send", "  U64:\t%lu %lu\n", cp->high, cp->low));
3644
293
    return 1;
3645
293
}
3646
3647
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3648
3649
3650
/**
3651
 * @internal
3652
 * builds an ASN object containing an signed int64.
3653
 *
3654
 * @see asn_build_signed_int64
3655
 * 
3656
 * @param pkt     IN/OUT address of the begining of the buffer.
3657
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3658
 * @param offset  IN/OUT offset to the start of the buffer where to write
3659
 * @param r       IN if not zero reallocate the buffer to fit the 
3660
 *                needed size.
3661
 * @param type    IN - type of object
3662
 * @param cp           IN - pointer to counter struct
3663
 * @param countersize  IN - size of input buffer
3664
 *
3665
 * @return 1 on success, 0 on error
3666
 */
3667
int
3668
asn_realloc_rbuild_signed_int64(u_char ** pkt, size_t * pkt_len,
3669
                                size_t * offset, int r,
3670
                                u_char type,
3671
                                const struct counter64 *cp, size_t countersize)
3672
143
{
3673
    /*
3674
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
3675
     */
3676
143
    register int32_t low = cp->low, high = cp->high;
3677
143
    size_t           intsize, start_offset = *offset;
3678
143
    int              count;
3679
143
    int32_t          testvalue = (high & 0x80000000) ? -1 : 0;
3680
3681
143
    if (countersize != sizeof(struct counter64)) {
3682
0
        _asn_size_err("build uint64", countersize,
3683
0
                      sizeof(struct counter64));
3684
0
        return 0;
3685
0
    }
3686
3687
    /*
3688
     * Encode the low 4 bytes first.  
3689
     */
3690
143
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3691
0
        return 0;
3692
0
    }
3693
143
    *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3694
143
    low >>= 8;
3695
143
    count = 1;
3696
3697
455
    while ((int) low != testvalue && count < 4) {
3698
312
        count++;
3699
312
        if (((*pkt_len - *offset) < 1)
3700
312
            && !(r && asn_realloc(pkt, pkt_len))) {
3701
0
            return 0;
3702
0
        }
3703
312
        *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3704
312
        low >>= 8;
3705
312
    }
3706
3707
    /*
3708
     * Then the high byte if present.  
3709
     */
3710
143
    if (high != testvalue) {
3711
        /*
3712
         * Do the rest of the low byte.  
3713
         */
3714
161
        for (; count < 4; count++) {
3715
58
            if (((*pkt_len - *offset) < 1)
3716
58
                && !(r && asn_realloc(pkt, pkt_len))) {
3717
0
                return 0;
3718
0
            }
3719
58
            *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
3720
58
        }
3721
3722
        /*
3723
         * Do high byte.  
3724
         */
3725
103
        if (((*pkt_len - *offset) < 1)
3726
103
            && !(r && asn_realloc(pkt, pkt_len))) {
3727
0
            return 0;
3728
0
        }
3729
103
        *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3730
103
        high >>= 8;
3731
3732
270
        while ((int) high != testvalue) {
3733
167
            if (((*pkt_len - *offset) < 1)
3734
167
                && !(r && asn_realloc(pkt, pkt_len))) {
3735
0
                return 0;
3736
0
            }
3737
167
            *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3738
167
            high >>= 8;
3739
167
        }
3740
103
    }
3741
3742
143
    if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) {
3743
        /*
3744
         * Make sure left most bit is representational of the rest of the bits
3745
         * that aren't encoded.  
3746
         */
3747
33
        if (((*pkt_len - *offset) < 1)
3748
33
            && !(r && asn_realloc(pkt, pkt_len))) {
3749
0
            return 0;
3750
0
        }
3751
33
        *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
3752
33
    }
3753
3754
143
    intsize = *offset - start_offset;
3755
3756
143
    while ((*pkt_len - *offset) < 5) {
3757
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3758
0
            return 0;
3759
0
        }
3760
0
    }
3761
3762
143
    *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3763
143
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_I64;
3764
143
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3765
3766
    /*
3767
     * Put the tag and length for the Opaque wrapper.  
3768
     */
3769
143
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3770
143
                                  ASN_OPAQUE, intsize + 3)) {
3771
143
        if (_asn_realloc_build_header_check
3772
143
            ("build counter u64", pkt, pkt_len, intsize + 3)) {
3773
0
            return 0;
3774
0
        }
3775
143
    } else {
3776
0
        return 0;
3777
0
    }
3778
3779
143
    DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
3780
143
    DEBUGMSG(("dumpv_send", "  UInt64:\t%lu %lu\n", cp->high, cp->low));
3781
143
    return 1;
3782
143
}
3783
3784
/**
3785
 * @internal
3786
 * builds an ASN object containing an float.
3787
 *
3788
 * @see asn_build_float
3789
 * 
3790
 * @param pkt     IN/OUT address of the begining of the buffer.
3791
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3792
 * @param offset  IN/OUT offset to the start of the buffer where to write
3793
 * @param r       IN if not zero reallocate the buffer to fit the 
3794
 *                needed size.
3795
 * @param type       IN - type of object
3796
 * @param floatp     IN - pointer to the float
3797
 * @param floatsize  IN - size of input buffer
3798
 *
3799
 * @return 1 on success, 0 on error
3800
 */
3801
3802
int
3803
asn_realloc_rbuild_float(u_char ** pkt, size_t * pkt_len,
3804
                         size_t * offset, int r,
3805
                         u_char type, const float *floatp, size_t floatsize)
3806
99
{
3807
99
    size_t          start_offset = *offset;
3808
99
    union {
3809
99
        float           floatVal;
3810
99
        int             intVal;
3811
99
        u_char          c[sizeof(float)];
3812
99
    } fu;
3813
3814
    /*
3815
     * Floatsize better not be larger than realistic.  
3816
     */
3817
99
    if (floatsize != sizeof(float) || floatsize > 122) {
3818
0
        return 0;
3819
0
    }
3820
3821
99
    while ((*pkt_len - *offset) < floatsize + 3) {
3822
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3823
0
            return 0;
3824
0
        }
3825
0
    }
3826
3827
    /*
3828
     * Correct for endian differences and copy value.  
3829
     */
3830
99
    fu.floatVal = *floatp;
3831
99
    fu.intVal = htonl(fu.intVal);
3832
99
    *offset += floatsize;
3833
99
    memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), floatsize);
3834
3835
    /*
3836
     * Put the special tag and length (3 bytes).  
3837
     */
3838
99
    *(*pkt + *pkt_len - (++*offset)) = (u_char) floatsize;
3839
99
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_FLOAT;
3840
99
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3841
3842
    /*
3843
     * Put the tag and length for the Opaque wrapper.  
3844
     */
3845
99
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3846
99
                                  ASN_OPAQUE, floatsize + 3)) {
3847
99
        if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
3848
99
                                            floatsize + 3)) {
3849
0
            return 0;
3850
99
        } else {
3851
99
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3852
99
                           *offset - start_offset);
3853
99
            DEBUGMSG(("dumpv_send", "Opaque Float:\t%f\n", *floatp));
3854
99
            return 1;
3855
99
        }
3856
99
    }
3857
3858
0
    return 0;
3859
99
}
3860
3861
/**
3862
 * @internal
3863
 * builds an ASN object containing an double.
3864
 *
3865
 * @see asn_build_double
3866
 * 
3867
 * @param pkt     IN/OUT address of the begining of the buffer.
3868
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3869
 * @param offset  IN/OUT offset to the start of the buffer where to write
3870
 * @param r       IN if not zero reallocate the buffer to fit the 
3871
 *                needed size.
3872
 * @param type    IN - type of object
3873
 * @param doublep           IN - pointer to double
3874
 * @param doublesize  IN - size of input buffer
3875
 *
3876
 * @return 1 on success, 0 on error
3877
 */
3878
3879
int
3880
asn_realloc_rbuild_double(u_char ** pkt, size_t * pkt_len,
3881
                          size_t * offset, int r,
3882
                          u_char type, const double *doublep, size_t doublesize)
3883
45
{
3884
45
    size_t          start_offset = *offset;
3885
45
    long            tmp;
3886
45
    union {
3887
45
        double          doubleVal;
3888
45
        int             intVal[2];
3889
45
        u_char          c[sizeof(double)];
3890
45
    } fu;
3891
3892
    /*
3893
     * Doublesize better not be larger than realistic.  
3894
     */
3895
45
    if (doublesize != sizeof(double) || doublesize > 122) {
3896
0
        return 0;
3897
0
    }
3898
3899
45
    while ((*pkt_len - *offset) < doublesize + 3) {
3900
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3901
0
            return 0;
3902
0
        }
3903
0
    }
3904
3905
    /*
3906
     * Correct for endian differences and copy value.  
3907
     */
3908
45
    fu.doubleVal = *doublep;
3909
45
    tmp = htonl(fu.intVal[0]);
3910
45
    fu.intVal[0] = htonl(fu.intVal[1]);
3911
45
    fu.intVal[1] = tmp;
3912
45
    *offset += doublesize;
3913
45
    memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), doublesize);
3914
3915
    /*
3916
     * Put the special tag and length (3 bytes).  
3917
     */
3918
45
    *(*pkt + *pkt_len - (++*offset)) = (u_char) doublesize;
3919
45
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_DOUBLE;
3920
45
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3921
3922
    /*
3923
     * Put the tag and length for the Opaque wrapper.  
3924
     */
3925
45
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3926
45
                                  ASN_OPAQUE, doublesize + 3)) {
3927
45
        if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
3928
45
                                            doublesize + 3)) {
3929
0
            return 0;
3930
45
        } else {
3931
45
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3932
45
                           *offset - start_offset);
3933
45
            DEBUGMSG(("dumpv_send", "  Opaque Double:\t%f\n", *doublep));
3934
45
            return 1;
3935
45
        }
3936
45
    }
3937
3938
0
    return 0;
3939
45
}
3940
3941
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3942
#endif                          /*  NETSNMP_USE_REVERSE_ASNENCODING  */
3943
/**
3944
 * @}
3945
 */