Coverage Report

Created: 2026-10-19 06:44

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