Coverage Report

Created: 2026-01-09 06:42

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