Coverage Report

Created: 2024-07-27 06:05

/src/net-snmp/snmplib/asn1.c
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Abstract Syntax Notation One, ASN.1
3
 * As defined in ISO/IS 8824 and ISO/IS 8825
4
 * This implements a subset of the above International Standards that
5
 * is sufficient to implement SNMP.
6
 *
7
 * Encodes abstract data types into a machine independent stream of bytes.
8
 *
9
 * Portions of this file are subject to the following copyright(s).  See
10
 * the Net-SNMP's COPYING file for more details and other copyrights
11
 * that may apply:
12
 *
13
 * Portions of this file are copyrighted by:
14
 * Copyright (c) 2016 VMware, Inc. All rights reserved.
15
 * Use is subject to license terms specified in the COPYING file
16
 * distributed with the Net-SNMP package.
17
 */
18
/**********************************************************************
19
  Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
20
21
                      All Rights Reserved
22
23
Permission to use, copy, modify, and distribute this software and its 
24
documentation for any purpose and without fee is hereby granted, 
25
provided that the above copyright notice appear in all copies and that
26
both that copyright notice and this permission notice appear in 
27
supporting documentation, and that the name of CMU not be
28
used in advertising or publicity pertaining to distribution of the
29
software without specific, written prior permission.  
30
31
CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
32
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
33
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
34
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
35
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
36
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
37
SOFTWARE.
38
******************************************************************/
39
/**
40
 * @defgroup asn1_packet_parse asn1 parsing and datatype manipulation routines.
41
 * @ingroup library
42
 *
43
 * @{
44
 * 
45
 * Note on 
46
 * 
47
 * Re-allocating reverse ASN.1 encoder functions.  Synopsis:
48
 *
49
 * \code
50
 *
51
 * u_char *buf = (u_char*)malloc(100);
52
 * u_char type = (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
53
 * size_t buf_len = 100, offset = 0;
54
 * long data = 12345;
55
 * int allow_realloc = 1;
56
 * 
57
 * if (asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
58
 *                            type, &data, sizeof(long)) == 0) {
59
 *     error;
60
 * }
61
 * 
62
 * \endcode
63
 *
64
 * NOTE WELL: after calling one of these functions with allow_realloc
65
 * non-zero, buf might have moved, buf_len might have grown and
66
 * offset will have increased by the size of the encoded data.
67
 * You should **NEVER** do something like this:
68
 * 
69
 * \code
70
 *
71
 * u_char *buf = (u_char *)malloc(100), *ptr;
72
 * u_char type = (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
73
 * size_t buf_len = 100, offset = 0;
74
 * long data1 = 1234, data2 = 5678;
75
 * int rc = 0, allow_realloc = 1;
76
 * 
77
 * rc  = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
78
 *                                type, &data1, sizeof(long));
79
 * ptr = buf[buf_len - offset];   / * points at encoding of data1 * /
80
 * if (rc == 0) {
81
 *      error;
82
 * }
83
 * rc  = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
84
 *                              type, &data2, sizeof(long));
85
 * make use of ptr here;
86
 * 
87
 * \endcode
88
 * 
89
 * ptr is **INVALID** at this point.  In general, you should store the
90
 * offset value and compute pointers when you need them:
91
 * 
92
 * 
93
 * \code
94
 *
95
 * u_char *buf = (u_char *)malloc(100), *ptr;
96
 * u_char type = (ASN_UNIVERSAL | ASN_PRIMITIVE | ASN_INTEGER);
97
 * size_t buf_len = 100, offset = 0, ptr_offset;
98
 * long data1 = 1234, data2 = 5678;
99
 * int rc = 0, allow_realloc = 1;
100
 * 
101
 * rc  = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
102
 *                              type, &data1, sizeof(long));
103
 * ptr_offset = offset;
104
 * if (rc == 0) {
105
 *      error;
106
 * }
107
 * rc  = asn_realloc_rbuild_int(&buf, &buf_len, &offset, allow_realloc,
108
 *                              type, &data2, sizeof(long));
109
 * ptr = buf + buf_len - ptr_offset
110
 * make use of ptr here;
111
 * 
112
 * \endcode
113
 * 
114
 * 
115
 * Here, you can see that ptr will be a valid pointer even if the block of
116
 * memory has been moved, as it may well have been.  Plenty of examples of
117
 * usage all over asn1.c, snmp_api.c, snmpusm.c.
118
 * 
119
 * The other thing you should **NEVER** do is to pass a pointer to a buffer
120
 * on the stack as the first argument when allow_realloc is non-zero, unless
121
 * you really know what you are doing and your machine/compiler allows you to
122
 * free non-heap memory.  There are rumours that such things exist, but many
123
 * consider them no more than the wild tales of a fool.
124
 * 
125
 * Of course, you can pass allow_realloc as zero, to indicate that you do not
126
 * wish the packet buffer to be reallocated for some reason; perhaps because
127
 * it is on the stack.  This may be useful to emulate the functionality of
128
 * the old API:
129
 *
130
 * \code 
131
 * 
132
 * u_char my_static_buffer[100], *cp = NULL;
133
 * size_t my_static_buffer_len = 100;
134
 * float my_pi = (float)22/(float)7;
135
 * 
136
 * cp = asn_rbuild_float(my_static_buffer, &my_static_buffer_len,
137
 *                       ASN_OPAQUE_FLOAT, &my_pi, sizeof(float));
138
 * if (cp == NULL) {
139
 * error;
140
 * }
141
 * 
142
 * \endcode
143
 * 
144
 * IS EQUIVALENT TO:
145
 * 
146
 * \code
147
 * 
148
 * u_char my_static_buffer[100];
149
 * size_t my_static_buffer_len = 100, my_offset = 0;
150
 * float my_pi = (float)22/(float)7;
151
 * int rc = 0;
152
 * 
153
 * rc = asn_realloc_rbuild_float(&my_static_buffer, &my_static_buffer_len,
154
 *                               &my_offset, 0,
155
 *                               ASN_OPAQUE_FLOAT, &my_pi, sizeof(float));
156
 * if (rc == 0) {
157
 *   error;
158
 * }
159
 * \endcode
160
 * 
161
 */
162
163
164
#include <net-snmp/net-snmp-config.h>
165
166
#ifdef KINETICS
167
#include "gw.h"
168
#endif
169
170
#ifdef HAVE_STRING_H
171
#include <string.h>
172
#else
173
#include <strings.h>
174
#endif
175
176
#include <sys/types.h>
177
#include <stdio.h>
178
#ifdef HAVE_STDINT_H
179
#include <stdint.h>
180
#endif
181
#ifdef HAVE_STDLIB_H
182
#include <stdlib.h>
183
#endif
184
#ifdef HAVE_NETINET_IN_H
185
#include <netinet/in.h>
186
#endif
187
188
#ifdef vms
189
#include <in.h>
190
#endif
191
192
#include <net-snmp/output_api.h>
193
#include <net-snmp/utilities.h>
194
195
#include <net-snmp/library/asn1.h>
196
#include <net-snmp/library/int64.h>
197
#include <net-snmp/library/mib.h>
198
199
#ifndef NULL
200
#define NULL  0
201
#endif
202
203
#include <net-snmp/library/snmp_api.h>
204
205
#ifndef INT32_MAX
206
#   define INT32_MAX 2147483647
207
#endif
208
209
#ifndef INT32_MIN
210
#   define INT32_MIN (0 - INT32_MAX - 1)
211
#endif
212
213
214
2.86k
#define CHECK_OVERFLOW_S(x,y) do {                                      \
215
2.86k
        if (x > INT32_MAX) {                                            \
216
21
            DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
217
21
            x &= 0xffffffff;                                            \
218
2.84k
        } else if (x < INT32_MIN) {                                     \
219
73
            DEBUGMSG(("asn","truncating signed value %ld to 32 bits (%d)\n",(long)(x),y)); \
220
73
            x = 0 - (x & 0xffffffff);                                   \
221
73
        }                                                               \
222
2.86k
    } while(0)
223
224
501
#define CHECK_OVERFLOW_U(x,y) do {                                      \
225
501
        if (x > UINT32_MAX) {                                           \
226
44
            x &= 0xffffffff;                                            \
227
44
            DEBUGMSG(("asn","truncating unsigned value to 32 bits (%d)\n",y)); \
228
44
        }                                                               \
229
501
    } 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
16
{
243
16
    char            ebuf[128];
244
245
16
    snprintf(ebuf, sizeof(ebuf),
246
16
            "%s size %lu: s/b %lu", str,
247
16
      (unsigned long)wrongsize, (unsigned long)rightsize);
248
16
    ebuf[ sizeof(ebuf)-1 ] = 0;
249
16
    ERROR_MSG(ebuf);
250
16
}
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
80
{
263
80
    char            ebuf[128];
264
265
80
    snprintf(ebuf, sizeof(ebuf), "%s type %d", str, wrongtype);
266
80
    ebuf[ sizeof(ebuf)-1 ] = 0;
267
80
    ERROR_MSG(ebuf);
268
80
}
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
75
{
282
75
    char            ebuf[128];
283
284
75
    snprintf(ebuf, sizeof(ebuf),
285
75
            "%s length %lu too large: exceeds %lu", str,
286
75
      (unsigned long)wrongsize, (unsigned long)rightsize);
287
75
    ebuf[ sizeof(ebuf)-1 ] = 0;
288
75
    ERROR_MSG(ebuf);
289
75
}
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
1.20k
{
302
1.20k
    char            ebuf[128];
303
304
1.20k
    snprintf(ebuf, sizeof(ebuf), "%s length %lu too short: need %lu", str,
305
1.20k
      (unsigned long)wrongsize, (unsigned long)rightsize);
306
1.20k
    ERROR_MSG(ebuf);
307
1.20k
}
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
10.1k
{
328
10.1k
    int len_len;
329
330
10.1k
    if (pkt_len < 1)
331
0
        return NULL;               /* always too short */
332
333
10.1k
    if (NULL == pkt || NULL == data_len)
334
0
        return NULL;
335
336
10.1k
    *data_len = 0;
337
338
10.1k
    if (*pkt & 0x80) {
339
        /*
340
         * long length; first byte is length of length (after masking high bit)
341
         */
342
1.00k
        len_len = (int) ((*pkt & ~0x80) + 1);
343
1.00k
        if (pkt_len < len_len)
344
84
            return NULL;           /* still too short for length and data */
345
346
        /* now we know we have enough data to parse length */
347
916
        if (NULL == asn_parse_length(pkt, data_len))
348
135
            return NULL;           /* propagate error from asn_parse_length */
349
9.11k
    } else {
350
        /*
351
         * short length; first byte is the length
352
         */
353
9.11k
        len_len = 1;
354
9.11k
        *data_len = *pkt;
355
9.11k
    }
356
357
9.89k
    if ((*data_len + len_len) > pkt_len)
358
674
        return NULL;
359
360
9.21k
    return (pkt + len_len);
361
9.89k
}
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
13
{
519
13
    char            ebuf[128];
520
521
13
    if (asn_length < 1) {
522
4
        snprintf(ebuf, sizeof(ebuf),
523
4
                "%s: length %d too small", str, (int) asn_length);
524
4
        ebuf[ sizeof(ebuf)-1 ] = 0;
525
4
        ERROR_MSG(ebuf);
526
4
        return 1;
527
4
    }
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
9
    return 0;
536
13
}
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
3.04k
{
564
    /*
565
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
566
     */
567
3.04k
    static const char *errpre = "parse int";
568
3.04k
    register u_char *bufp = data;
569
3.04k
    u_long          asn_length;
570
3.04k
    int             i;
571
3.04k
    union {
572
3.04k
        long          l;
573
3.04k
        unsigned char b[sizeof(long)];
574
3.04k
    } value;
575
576
3.04k
    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
3.04k
    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
3.04k
    if (*datalength < 2) {
588
15
        _asn_short_err(errpre, *datalength, 2);
589
15
        return NULL;
590
15
    }
591
592
3.03k
    *type = *bufp++;
593
3.03k
    if (*type != ASN_INTEGER) {
594
17
        _asn_type_err(errpre, *type);
595
17
        return NULL;
596
17
    }
597
598
3.01k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
599
3.01k
    if (NULL == bufp) {
600
130
        _asn_short_err(errpre, *datalength - 1, asn_length);
601
130
        return NULL;
602
130
    }
603
604
2.88k
    if ((size_t) asn_length > intsize || (int) asn_length == 0) {
605
25
        _asn_length_err(errpre, (size_t) asn_length, intsize);
606
25
        return NULL;
607
25
    }
608
609
2.86k
    *datalength -= (int) asn_length + (bufp - data);
610
611
2.86k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
612
613
2.86k
    memset(&value.b, *bufp & 0x80 ? 0xff : 0, sizeof(value.b));
614
2.86k
    if (NETSNMP_BIGENDIAN) {
615
0
        for (i = sizeof(long) - asn_length; asn_length--; i++)
616
0
            value.b[i] = *bufp++;
617
2.86k
    } else {
618
8.03k
        for (i = asn_length - 1; asn_length--; i--)
619
5.17k
            value.b[i] = *bufp++;
620
2.86k
    }
621
622
2.86k
    CHECK_OVERFLOW_S(value.l, 1);
623
624
2.86k
    DEBUGMSG(("dumpv_recv", "  Integer:\t%ld (0x%.2lX)\n", value.l, value.l));
625
626
2.86k
    *intp = value.l;
627
2.86k
    return bufp;
628
2.88k
}
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
256
{
657
    /*
658
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
659
     */
660
256
    static const char *errpre = "parse uint";
661
256
    register u_char *bufp = data;
662
256
    u_long          asn_length;
663
256
    register u_long value = 0;
664
665
256
    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
256
    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
256
    if (*datalength < 2) {
677
3
        _asn_short_err(errpre, *datalength, 2);
678
3
        return NULL;
679
3
    }
680
681
253
    *type = *bufp++;
682
253
    if (*type != ASN_COUNTER && *type != ASN_GAUGE && *type != ASN_TIMETICKS
683
253
            && *type != ASN_UINTEGER) {
684
17
        _asn_type_err(errpre, *type);
685
17
        return NULL;
686
17
    }
687
688
236
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
689
236
    if (NULL == bufp) {
690
113
        _asn_short_err(errpre, *datalength - 1, asn_length);
691
113
        return NULL;
692
113
    }
693
694
123
    if ((asn_length > (intsize + 1)) || ((int) asn_length == 0) ||
695
123
        ((asn_length == intsize + 1) && *bufp != 0x00)) {
696
12
        _asn_length_err(errpre, (size_t) asn_length, intsize);
697
12
        return NULL;
698
12
    }
699
111
    *datalength -= (int) asn_length + (bufp - data);
700
701
111
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
702
703
696
    while (asn_length--)
704
585
        value = (value << 8) | *bufp++;
705
706
111
    CHECK_OVERFLOW_U(value,2);
707
708
111
    DEBUGMSG(("dumpv_recv", "  UInteger:\t%ld (0x%.2lX)\n", value, value));
709
710
111
    *intp = value;
711
111
    return bufp;
712
123
}
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
1.61k
{
917
1.61k
    static const char *errpre = "parse string";
918
1.61k
    u_char         *bufp = data;
919
1.61k
    u_long          asn_length;
920
921
1.61k
    if (NULL == data || NULL == datalength || NULL == type || NULL == str ||
922
1.61k
        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
1.61k
    if (*datalength < 2) {
929
212
        _asn_short_err(errpre, *datalength, 2);
930
212
        return NULL;
931
212
    }
932
933
1.40k
    *type = *bufp++;
934
1.40k
    if (*type != ASN_OCTET_STR && *type != ASN_IPADDRESS && *type != ASN_OPAQUE
935
1.40k
            && *type != ASN_NSAP) {
936
30
        _asn_type_err(errpre, *type);
937
30
        return NULL;
938
30
    }
939
940
1.37k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
941
1.37k
    if (NULL == bufp) {
942
131
        _asn_short_err(errpre, *datalength - 1, asn_length);
943
131
        return NULL;
944
131
    }
945
946
1.24k
    if (asn_length > *strlength) {
947
20
        _asn_length_err(errpre, (size_t) asn_length, *strlength);
948
20
        return NULL;
949
20
    }
950
951
1.22k
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
952
953
1.22k
    memmove(str, bufp, asn_length);
954
1.22k
    if (*strlength > asn_length)
955
1.12k
        str[asn_length] = 0;
956
1.22k
    *strlength = asn_length;
957
1.22k
    *datalength -= asn_length + (bufp - data);
958
959
1.22k
    DEBUGIF("dumpv_recv") {
960
1.22k
        u_char         *buf = (u_char *) malloc(1 + asn_length);
961
1.22k
        size_t          l = (buf != NULL) ? (1 + asn_length) : 0, ol = 0;
962
963
1.22k
        if (sprint_realloc_asciistring
964
1.22k
            (&buf, &l, &ol, 1, str, asn_length)) {
965
1.22k
            DEBUGMSG(("dumpv_recv", "  String:\t%s\n", buf));
966
1.22k
        } else {
967
0
            if (buf == NULL) {
968
0
                DEBUGMSG(("dumpv_recv", "  String:\t[TRUNCATED]\n"));
969
0
            } else {
970
0
                DEBUGMSG(("dumpv_recv", "  String:\t%s [TRUNCATED]\n",
971
0
                          buf));
972
0
            }
973
0
        }
974
1.22k
        if (buf != NULL) {
975
1.22k
            free(buf);
976
1.22k
        }
977
1.22k
    }
978
979
1.22k
    return bufp + asn_length;
980
1.24k
}
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
4.20k
{
1078
4.20k
    register u_char *bufp;
1079
4.20k
    u_long          asn_length = 0;
1080
4.20k
    const char      *errpre = "parse header";
1081
1082
4.20k
    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
4.20k
    if (*datalength < 2) {
1089
75
        _asn_short_err(errpre, *datalength, 2);
1090
75
        return NULL;
1091
75
    }
1092
1093
4.13k
    bufp = data;
1094
    /*
1095
     * this only works on data types < 30, i.e. no extension octets 
1096
     */
1097
4.13k
    if (IS_EXTENSION_ID(*bufp)) {
1098
32
        ERROR_MSG("can't process ID >= 30");
1099
32
        return NULL;
1100
32
    }
1101
4.10k
    *type = *bufp++;
1102
1103
4.10k
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1104
4.10k
    if (NULL == bufp) {
1105
389
        _asn_short_err(errpre, *datalength - 1, asn_length);
1106
389
        return NULL;
1107
389
    }
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
3.71k
#endif
1119
1120
3.71k
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1121
1122
3.71k
    if ((asn_length > 2) && (*type == ASN_OPAQUE) && (*bufp == ASN_OPAQUE_TAG1)) {
1123
1124
        /*
1125
         * check if 64-but counter 
1126
         */
1127
144
        switch (*(bufp + 1)) {
1128
4
        case ASN_OPAQUE_COUNTER64:
1129
19
        case ASN_OPAQUE_U64:
1130
26
        case ASN_OPAQUE_FLOAT:
1131
34
        case ASN_OPAQUE_DOUBLE:
1132
141
        case ASN_OPAQUE_I64:
1133
141
            *type = *(bufp + 1);
1134
141
            break;
1135
1136
3
        default:
1137
            /*
1138
             * just an Opaque 
1139
             */
1140
3
            *datalength = (int) asn_length;
1141
3
            return bufp;
1142
144
        }
1143
        /*
1144
         * value is encoded as special format 
1145
         */
1146
141
        *datalength = (int) asn_length;
1147
141
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
1148
141
        if (NULL == bufp) {
1149
9
            _asn_short_err("parse opaque header", *datalength - 2, asn_length);
1150
9
            return NULL;
1151
9
        }
1152
141
    }
1153
3.70k
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
1154
1155
3.70k
    *datalength = (int) asn_length;
1156
1157
3.70k
    return bufp;
1158
3.71k
}
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
2.93k
{                               /* error message prefix */
1178
2.93k
    data = asn_parse_header(data, datalength, type);
1179
2.93k
    if (data && (*type != expected_type)) {
1180
169
        char            ebuf[128];
1181
169
        snprintf(ebuf, sizeof(ebuf),
1182
169
                 "%s header type %02X: s/b %02X", estr,
1183
169
                (u_char) * type, (u_char) expected_type);
1184
169
        ebuf[ sizeof(ebuf)-1 ] = 0;
1185
169
        ERROR_MSG(ebuf);
1186
169
        return NULL;
1187
169
    }
1188
2.76k
    return data;
1189
2.93k
}
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
916
{
1303
916
    static const char *errpre = "parse length";
1304
916
    char            ebuf[128];
1305
916
    register u_char lengthbyte;
1306
1307
916
    if (!data || !length) {
1308
0
        ERROR_MSG("parse length: NULL pointer");
1309
0
        return NULL;
1310
0
    }
1311
916
    lengthbyte = *data;
1312
1313
916
    if (lengthbyte & ASN_LONG_LEN) {
1314
916
        lengthbyte &= ~ASN_LONG_LEN;    /* turn MSb off */
1315
916
        if (lengthbyte == 0) {
1316
35
            snprintf(ebuf, sizeof(ebuf),
1317
35
                     "%s: indefinite length not supported", errpre);
1318
35
            ebuf[ sizeof(ebuf)-1 ] = 0;
1319
35
            ERROR_MSG(ebuf);
1320
35
            return NULL;
1321
35
        }
1322
881
        if (lengthbyte > sizeof(long)) {
1323
35
            snprintf(ebuf, sizeof(ebuf),
1324
35
                    "%s: data length %d > %lu not supported", errpre,
1325
35
                    lengthbyte, (unsigned long)sizeof(long));
1326
35
            ebuf[ sizeof(ebuf)-1 ] = 0;
1327
35
            ERROR_MSG(ebuf);
1328
35
            return NULL;
1329
35
        }
1330
846
        data++;
1331
846
        *length = 0;            /* protect against short lengths */
1332
4.63k
        while (lengthbyte--) {
1333
3.79k
            *length <<= 8;
1334
3.79k
            *length |= *data++;
1335
3.79k
        }
1336
846
        if ((long) *length < 0) {
1337
65
            snprintf(ebuf, sizeof(ebuf),
1338
65
                     "%s: negative data length %ld\n", errpre,
1339
65
                     (long) *length);
1340
65
            ebuf[ sizeof(ebuf)-1 ] = 0;
1341
65
            ERROR_MSG(ebuf);
1342
65
            return NULL;
1343
65
        }
1344
781
        return data;
1345
846
    } else {                    /* short asnlength */
1346
0
        *length = (long) lengthbyte;
1347
0
        return data + 1;
1348
0
    }
1349
916
}
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
872
{
1451
872
    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
872
    register u_char *bufp = data;
1459
872
    register oid   *oidp = objid + 1;
1460
872
    register u_long subidentifier;
1461
872
    register long   length;
1462
872
    u_long          asn_length;
1463
872
    size_t          original_length = *objidlength;
1464
1465
872
    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
872
    if (*datalength < 2) {
1472
6
        _asn_short_err(errpre, *datalength, 2);
1473
6
        return NULL;
1474
6
    }
1475
1476
866
    *type = *bufp++;
1477
866
    if (*type != ASN_OBJECT_ID) {
1478
4
        _asn_type_err(errpre, *type);
1479
4
        return NULL;
1480
4
    }
1481
862
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1482
862
    if (NULL == bufp) {
1483
121
        _asn_short_err(errpre, *datalength - 1, asn_length);
1484
121
        return NULL;
1485
121
    }
1486
1487
741
    *datalength -= (int) asn_length + (bufp - data);
1488
1489
741
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
1490
1491
    /*
1492
     * Handle invalid object identifier encodings of the form 06 00 robustly 
1493
     */
1494
741
    if (asn_length == 0)
1495
275
        objid[0] = objid[1] = 0;
1496
1497
741
    length = asn_length;
1498
741
    (*objidlength)--;           /* account for expansion of first byte */
1499
1500
2.80k
    while (length > 0 && (*objidlength)-- > 0) {
1501
2.08k
        subidentifier = 0;
1502
2.50k
        do {                    /* shift and add in low order 7 bits */
1503
2.50k
            subidentifier =
1504
2.50k
                (subidentifier << 7) + (*(u_char *) bufp & ~ASN_BIT8);
1505
2.50k
            length--;
1506
2.50k
        } while ((*(u_char *) bufp++ & ASN_BIT8) && (length > 0));        /* last byte has high bit clear */
1507
1508
2.08k
  if (length == 0) {
1509
464
            u_char *last_byte = bufp - 1;
1510
464
            if (*last_byte & ASN_BIT8) {
1511
                /* last byte has high bit set -> wrong BER encoded OID */
1512
14
                ERROR_MSG("subidentifier syntax error");
1513
14
                return NULL;
1514
14
            }
1515
464
        }
1516
2.06k
        if (subidentifier > MAX_SUBID) {
1517
3
            ERROR_MSG("subidentifier too large");
1518
3
            return NULL;
1519
3
        }
1520
2.06k
        *oidp++ = (oid) subidentifier;
1521
2.06k
    }
1522
1523
724
    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
724
    subidentifier = oidp - objid >= 2 ? objid[1] : 0;
1536
724
    if (subidentifier == 0x2B) {
1537
13
        objid[0] = 1;
1538
13
        objid[1] = 3;
1539
711
    } else {
1540
711
        if (subidentifier < 40) {
1541
433
            objid[0] = 0;
1542
433
            objid[1] = subidentifier;
1543
433
        } else if (subidentifier < 80) {
1544
99
            objid[0] = 1;
1545
99
            objid[1] = subidentifier - 40;
1546
179
        } else {
1547
179
            objid[0] = 2;
1548
179
            objid[1] = subidentifier - 80;
1549
179
        }
1550
711
    }
1551
1552
724
    *objidlength = (int) (oidp - objid);
1553
1554
724
    DEBUGMSG(("dumpv_recv", "  ObjID: "));
1555
724
    DEBUGMSGOID(("dumpv_recv", objid, *objidlength));
1556
724
    DEBUGMSG(("dumpv_recv", "\n"));
1557
724
    return bufp;
1558
724
}
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
            ERROR_MSG("build objid: bad second subidentifier");
1641
0
            return NULL;
1642
0
        }
1643
0
        objid_val = objid[0] * 40 + objid[1];
1644
0
    }
1645
0
    first_objid_val = objid_val;
1646
0
    CHECK_OVERFLOW_U(first_objid_val, 14);
1647
1648
    /*
1649
     * ditch illegal calls now 
1650
     */
1651
0
    if (objidlength > MAX_OID_LEN)
1652
0
        return NULL;
1653
1654
    /*
1655
     * calculate the number of bytes needed to store the encoded value 
1656
     */
1657
0
    if (objidlength <= 1) {
1658
0
        asnlength = encoded_oid_len(first_objid_val);
1659
0
    } else {
1660
0
        asnlength = 0;
1661
0
        for (i = 1; i < objidlength; i++) {
1662
0
            objid_val = i == 1 ? first_objid_val : objid[i];
1663
0
            CHECK_OVERFLOW_U(objid_val, 5);
1664
0
            asnlength += encoded_oid_len(objid_val);
1665
0
        }
1666
0
    }
1667
1668
    /*
1669
     * store the ASN.1 tag and length 
1670
     */
1671
0
    data = asn_build_header(data, datalength, type, asnlength);
1672
0
    if (_asn_build_header_check("build objid", data, *datalength, asnlength))
1673
0
        return NULL;
1674
1675
    /*
1676
     * store the encoded OID value 
1677
     */
1678
0
    if (objidlength <= 1) {
1679
0
        *data++ = 0;
1680
0
    } else {
1681
0
        for (i = 1; i < objidlength; i++) {
1682
0
            unsigned int encoded_len;
1683
0
            int j;
1684
1685
0
            objid_val = (uint32_t)(i == 1 ? first_objid_val : objid[i]);
1686
0
            encoded_len = encoded_oid_len(objid_val);
1687
0
            for (j = encoded_len - 1; j >= 0; j--) {
1688
0
                data[j] = (objid_val & 0x7f) |
1689
0
                    (j == encoded_len - 1 ? 0 : 0x80);
1690
0
                objid_val >>= 7;
1691
0
            }
1692
0
            data += encoded_len;
1693
0
        }
1694
0
    }
1695
1696
    /*
1697
     * return the length and data ptr 
1698
     */
1699
0
    *datalength -= asnlength;
1700
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1701
0
    DEBUGMSG(("dumpv_send", "  ObjID: "));
1702
0
    DEBUGMSGOID(("dumpv_send", objid, objidlength));
1703
0
    DEBUGMSG(("dumpv_send", "\n"));
1704
0
    return data;
1705
0
}
1706
1707
/**
1708
 * @internal
1709
 * asn_parse_null - Interprets an ASN null type.
1710
 *
1711
 *  On entry, datalength is input as the number of valid bytes following
1712
 *   "data".  On exit, it is returned as the number of valid bytes
1713
 *   following the beginning of the next object.
1714
 *
1715
 *  Returns a pointer to the first byte past the end
1716
 *   of this object (i.e. the start of the next object).
1717
 *  Returns NULL on any error.
1718
 *
1719
 * @param data         IN - pointer to start of object
1720
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1721
 * @param type         OUT - asn type of object
1722
 *  @return Returns a pointer to the first byte past the end
1723
 *          of this object (i.e. the start of the next object).
1724
 *          Returns NULL on any error.
1725
 */
1726
u_char         *
1727
asn_parse_null(u_char * data, size_t * datalength, u_char * type)
1728
0
{
1729
    /*
1730
     * ASN.1 null ::= 0x05 0x00
1731
     */
1732
0
    register u_char *bufp = data;
1733
0
    u_long          asn_length;
1734
0
    static const char *errpre = "parse null";
1735
1736
0
    if (NULL == data || NULL == datalength || NULL == type) {
1737
0
        ERROR_MSG("parse null: NULL pointer");
1738
0
        return NULL;
1739
0
    }
1740
1741
    /** need at least 2 bytes to work with: type, length  (which should be 0) */
1742
0
    if (*datalength < 2) {
1743
0
        _asn_short_err(errpre, *datalength, 2);
1744
0
        return NULL;
1745
0
    }
1746
1747
0
    *type = *bufp++;
1748
0
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1749
0
    if (NULL == bufp) {
1750
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1751
0
        return NULL;
1752
0
    }
1753
0
    if (asn_length != 0) {
1754
0
        ERROR_MSG("parse null: malformed ASN.1 null");
1755
0
        return NULL;
1756
0
    }
1757
1758
0
    *datalength -= (bufp - data);
1759
1760
0
    DEBUGDUMPSETUP("recv", data, bufp - data);
1761
0
    DEBUGMSG(("dumpv_recv", "  NULL\n"));
1762
1763
0
    return bufp + asn_length;
1764
0
}
1765
1766
1767
/**
1768
 * @internal
1769
 * asn_build_null - Builds an ASN null object.
1770
 *
1771
 *  On entry, datalength is input as the number of valid bytes following
1772
 *   "data".  On exit, it is returned as the number of valid bytes
1773
 *   following the beginning of the next object.
1774
 *
1775
 *  Returns a pointer to the first byte past the end
1776
 *   of this object (i.e. the start of the next object).
1777
 *  Returns NULL on any error.
1778
 *
1779
 * @param data         IN - pointer to start of object
1780
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1781
 * @param type         IN - asn type of object
1782
 * @retun  Returns a pointer to the first byte past the end
1783
 *         of this object (i.e. the start of the next object).
1784
 *         Returns NULL on any error.
1785
 *
1786
 */
1787
u_char         *
1788
asn_build_null(u_char * data, size_t * datalength, u_char type)
1789
0
{
1790
    /*
1791
     * ASN.1 null ::= 0x05 0x00
1792
     */
1793
0
    u_char         *initdatap = data;
1794
0
    data = asn_build_header(data, datalength, type, 0);
1795
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
1796
0
    DEBUGMSG(("dumpv_send", "  NULL\n"));
1797
0
    return data;
1798
0
}
1799
1800
/**
1801
 * @internal
1802
 * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
1803
 *
1804
 *  On entry, datalength is input as the number of valid bytes following
1805
 *   "data".  On exit, it is returned as the number of valid bytes
1806
 *   following the beginning of the next object.
1807
 *
1808
 *  "string" is filled with the bit string.
1809
 *
1810
 *  Returns a pointer to the first byte past the end
1811
 *   of this object (i.e. the start of the next object).
1812
 *  Returns NULL on any error.
1813
 *
1814
 * @param data         IN - pointer to start of object
1815
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1816
 * @param type         OUT - asn type of object
1817
 * @param string       IN/OUT - pointer to start of output buffer
1818
 * @param strlength    IN/OUT - size of output buffer
1819
 * @return Returns a pointer to the first byte past the end
1820
 *         of this object (i.e. the start of the next object).
1821
 *         Returns NULL on any error.
1822
 */
1823
u_char         *
1824
asn_parse_bitstring(u_char * data,
1825
                    size_t * datalength,
1826
                    u_char * type, u_char * str, size_t * strlength)
1827
13
{
1828
    /*
1829
     * bitstring ::= 0x03 asnlength unused {byte}*
1830
     */
1831
13
    static const char *errpre = "parse bitstring";
1832
13
    register u_char *bufp = data;
1833
13
    u_long          asn_length;
1834
1835
13
    if (NULL == data || NULL == datalength || NULL == type ||
1836
13
        NULL == str || NULL == strlength) {
1837
0
        ERROR_MSG("parse bitstring: NULL pointer");
1838
0
        return NULL;
1839
0
    }
1840
1841
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
1842
13
    if (*datalength < 2) {
1843
0
        _asn_short_err(errpre, *datalength, 2);
1844
0
        return NULL;
1845
0
    }
1846
1847
13
    *type = *bufp++;
1848
13
    if (*type != ASN_BIT_STR) {
1849
0
        _asn_type_err(errpre, *type);
1850
0
        return NULL;
1851
0
    }
1852
1853
13
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1854
13
    if (NULL == bufp) {
1855
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1856
0
        return NULL;
1857
0
    }
1858
1859
13
    if ((size_t) asn_length > *strlength) {
1860
0
        _asn_length_err(errpre, (size_t) asn_length, *strlength);
1861
0
        return NULL;
1862
0
    }
1863
13
    if (_asn_bitstring_check(errpre, asn_length, *bufp))
1864
4
        return NULL;
1865
1866
9
    DEBUGDUMPSETUP("recv", data, bufp - data);
1867
9
    DEBUGMSG(("dumpv_recv", "  Bitstring: "));
1868
9
    DEBUGMSGHEX(("dumpv_recv", data, asn_length));
1869
9
    DEBUGMSG(("dumpv_recv", "\n"));
1870
1871
9
    memmove(str, bufp, asn_length);
1872
9
    *strlength = (int) asn_length;
1873
9
    *datalength -= (int) asn_length + (bufp - data);
1874
9
    return bufp + asn_length;
1875
13
}
1876
1877
1878
/**
1879
 * @internal
1880
 * asn_build_bitstring - Builds an ASN bit string object containing the
1881
 * input string.
1882
 *
1883
 *  On entry, datalength is input as the number of valid bytes following
1884
 *   "data".  On exit, it is returned as the number of valid bytes
1885
 *   following the beginning of the next object.
1886
 *
1887
 *  Returns a pointer to the first byte past the end
1888
 *   of this object (i.e. the start of the next object).
1889
 *  Returns NULL on any error.
1890
 *
1891
 * @param data         IN - pointer to start of object
1892
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1893
 * @param type         IN - asn type of object
1894
 * @param string       IN - pointer to start of input buffer
1895
 * @param strlength    IN - size of input buffer
1896
 * @return Returns a pointer to the first byte past the end
1897
 *         of this object (i.e. the start of the next object).
1898
 *         Returns NULL on any error.
1899
 */
1900
u_char         *
1901
asn_build_bitstring(u_char * data,
1902
                    size_t * datalength,
1903
                    u_char type, const u_char * str, size_t strlength)
1904
0
{
1905
    /*
1906
     * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
1907
     */
1908
0
    static const char *errpre = "build bitstring";
1909
0
    if (_asn_bitstring_check
1910
0
        (errpre, strlength, (u_char)((str) ? *str :  0)))
1911
0
        return NULL;
1912
1913
0
    data = asn_build_header(data, datalength, type, strlength);
1914
0
    if (_asn_build_header_check(errpre, data, *datalength, strlength))
1915
0
        return NULL;
1916
1917
0
    if (strlength > 0 && str)
1918
0
        memmove(data, str, strlength);
1919
0
    else if (strlength > 0 && !str) {
1920
0
        ERROR_MSG("no string passed into asn_build_bitstring\n");
1921
0
        return NULL;
1922
0
    }
1923
1924
0
    *datalength -= strlength;
1925
0
    DEBUGDUMPSETUP("send", data, strlength);
1926
0
    DEBUGMSG(("dumpv_send", "  Bitstring: "));
1927
0
    DEBUGMSGHEX(("dumpv_send", data, strlength));
1928
0
    DEBUGMSG(("dumpv_send", "\n"));
1929
0
    return data + strlength;
1930
0
}
1931
1932
/**
1933
 * @internal
1934
 * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
1935
 * type.
1936
 *
1937
 *  On entry, datalength is input as the number of valid bytes following
1938
 *   "data".  On exit, it is returned as the number of valid bytes
1939
 *   following the end of this object.
1940
 *
1941
 *  Returns a pointer to the first byte past the end
1942
 *   of this object (i.e. the start of the next object).
1943
 *  Returns NULL on any error.
1944
 *
1945
 * @param data         IN - pointer to start of object
1946
 * @param datalength   IN/OUT - number of valid bytes left in buffer
1947
 * @param type         OUT - asn type of object
1948
 * @param cp           IN/OUT - pointer to counter struct
1949
 * @param countersize  IN - size of output buffer
1950
 * @return  Returns a pointer to the first byte past the end
1951
 *          of this object (i.e. the start of the next object).
1952
 *          Returns NULL on any error.
1953
 */
1954
u_char         *
1955
asn_parse_unsigned_int64(u_char * data,
1956
                         size_t * datalength,
1957
                         u_char * type,
1958
                         struct counter64 *cp, size_t countersize)
1959
113
{
1960
    /*
1961
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1962
     */
1963
113
    static const char *errpre = "parse uint64";
1964
113
    const int       uint64sizelimit = (4 * 2) + 1;
1965
113
    register u_char *bufp = data;
1966
113
    u_long          asn_length;
1967
113
    register u_long low = 0, high = 0;
1968
1969
113
    if (countersize != sizeof(struct counter64)) {
1970
0
        _asn_size_err(errpre, countersize, sizeof(struct counter64));
1971
0
        return NULL;
1972
0
    }
1973
1974
113
    if (NULL == data || NULL == datalength || NULL == type || NULL == cp) {
1975
0
        ERROR_MSG("parse uint64: NULL pointer");
1976
0
        return NULL;
1977
0
    }
1978
1979
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
1980
113
    if (*datalength < 2) {
1981
0
        _asn_short_err(errpre, *datalength, 2);
1982
0
        return NULL;
1983
0
    }
1984
1985
113
    *type = *bufp++;
1986
113
    if (*type != ASN_COUNTER64
1987
113
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
1988
113
            && *type != ASN_OPAQUE
1989
113
#endif
1990
113
            ) {
1991
2
        _asn_type_err(errpre, *type);
1992
2
        return NULL;
1993
2
    }
1994
111
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
1995
111
    if (NULL == bufp) {
1996
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
1997
0
        return NULL;
1998
0
    }
1999
2000
111
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2001
111
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2002
    /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_<type> */
2003
111
    if ((*type == ASN_OPAQUE) && (asn_length < 2)) {
2004
0
        _asn_short_err(errpre, asn_length, 2);
2005
0
        return NULL;
2006
0
    }
2007
2008
    /*
2009
     * 64 bit counters as opaque 
2010
     */
2011
111
    if ((*type == ASN_OPAQUE) &&
2012
111
        (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
2013
111
        (*bufp == ASN_OPAQUE_TAG1) &&
2014
111
        ((*(bufp + 1) == ASN_OPAQUE_COUNTER64) ||
2015
12
         (*(bufp + 1) == ASN_OPAQUE_U64))) {
2016
        /*
2017
         * change type to Counter64 or U64 
2018
         */
2019
12
        *type = *(bufp + 1);
2020
        /*
2021
         * value is encoded as special format 
2022
         */
2023
12
        *datalength = asn_length;
2024
12
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2025
12
        if (NULL == bufp) {
2026
0
            _asn_short_err("parse opaque uint64", *datalength - 2, asn_length);
2027
0
            return NULL;
2028
0
        }
2029
12
    }
2030
111
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2031
111
    if (((int) asn_length > uint64sizelimit) ||
2032
111
        (((int) asn_length == uint64sizelimit) && *bufp != 0x00)) {
2033
10
        _asn_length_err(errpre, (size_t) asn_length, uint64sizelimit);
2034
10
        return NULL;
2035
10
    }
2036
101
    *datalength -= (int) asn_length + (bufp - data);
2037
788
    while (asn_length--) {
2038
687
        high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
2039
687
        low = ((low & 0x00FFFFFF) << 8) | *bufp++;
2040
687
    }
2041
2042
101
    CHECK_OVERFLOW_U(high,6);
2043
101
    CHECK_OVERFLOW_U(low,6);
2044
2045
101
    cp->low = low;
2046
101
    cp->high = high;
2047
2048
101
    DEBUGIF("dumpv_recv") {
2049
101
        char            i64buf[I64CHARSZ + 1];
2050
101
        printU64(i64buf, cp);
2051
101
        DEBUGMSG(("dumpv_recv", "Counter64: %s\n", i64buf));
2052
101
    }
2053
2054
101
    return bufp;
2055
111
}
2056
2057
2058
/**
2059
 * @internal
2060
 * asn_build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
2061
 *
2062
 *  On entry, datalength is input as the number of valid bytes following
2063
 *   "data".  On exit, it is returned as the number of valid bytes
2064
 *   following the end of this object.
2065
 *
2066
 *  Returns a pointer to the first byte past the end
2067
 *   of this object (i.e. the start of the next object).
2068
 *  Returns NULL on any error.
2069
 *
2070
 * @param data         IN - pointer to start of output buffer
2071
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2072
 * @param type         IN  - asn type of object
2073
 * @param cp           IN - pointer to counter struct
2074
 * @param countersize  IN - size of input buffer
2075
 * @return  Returns a pointer to the first byte past the end
2076
 *          of this object (i.e. the start of the next object).
2077
 *          Returns NULL on any error.
2078
 */
2079
u_char         *
2080
asn_build_unsigned_int64(u_char * data,
2081
                         size_t * datalength,
2082
                         u_char type,
2083
                         const struct counter64 *cp, size_t countersize)
2084
0
{
2085
    /*
2086
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
2087
     */
2088
2089
0
    uint64_t        value;
2090
0
    int             add_null_byte = 0;
2091
0
    size_t          intsize = 8;
2092
0
    u_char         *initdatap = data;
2093
2094
0
    if (countersize != sizeof(struct counter64)) {
2095
0
        _asn_size_err("build uint64", countersize, sizeof(struct counter64));
2096
0
        return NULL;
2097
0
    }
2098
2099
0
    {
2100
0
        u_long high = cp->high, low = cp->low;
2101
2102
0
        CHECK_OVERFLOW_U(high,7);
2103
0
        CHECK_OVERFLOW_U(low,7);
2104
2105
0
        value = ((uint64_t)cp->high << 32) | cp->low;
2106
0
    }
2107
2108
0
    if (value >> 63) {
2109
        /*
2110
         * if MSB is set 
2111
         */
2112
0
        add_null_byte = 1;
2113
0
        intsize++;
2114
0
    } else {
2115
        /*
2116
         * Truncate "unnecessary" bytes off of the most significant end of this
2117
         * 2's complement integer.
2118
         * There should be no sequence of 9 consecutive 1's or 0's at the most
2119
         * significant end of the integer.
2120
         */
2121
0
        static const uint64_t mask = 0xff8ull << 52;
2122
0
        while (((value & mask) == 0 || (value & mask) == mask) && intsize > 1) {
2123
0
            intsize--;
2124
0
            value <<= 8;
2125
0
        }
2126
0
    }
2127
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2128
    /*
2129
     * encode a Counter64 as an opaque (it also works in SNMPv1) 
2130
     */
2131
    /*
2132
     * turn into Opaque holding special tagged value 
2133
     */
2134
0
    if (type == ASN_OPAQUE_COUNTER64) {
2135
        /*
2136
         * put the tag and length for the Opaque wrapper 
2137
         */
2138
0
        data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2139
0
        if (_asn_build_header_check
2140
0
            ("build counter u64", data, *datalength, intsize + 3))
2141
0
            return NULL;
2142
2143
        /*
2144
         * put the special tag and length 
2145
         */
2146
0
        *data++ = ASN_OPAQUE_TAG1;
2147
0
        *data++ = ASN_OPAQUE_COUNTER64;
2148
0
        *data++ = (u_char) intsize;
2149
0
        *datalength = *datalength - 3;
2150
0
    } else
2151
        /*
2152
         * Encode the Unsigned int64 in an opaque 
2153
         */
2154
        /*
2155
         * turn into Opaque holding special tagged value 
2156
         */
2157
0
    if (type == ASN_OPAQUE_U64) {
2158
        /*
2159
         * put the tag and length for the Opaque wrapper 
2160
         */
2161
0
        data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2162
0
        if (_asn_build_header_check
2163
0
            ("build opaque u64", data, *datalength, intsize + 3))
2164
0
            return NULL;
2165
2166
        /*
2167
         * put the special tag and length 
2168
         */
2169
0
        *data++ = ASN_OPAQUE_TAG1;
2170
0
        *data++ = ASN_OPAQUE_U64;
2171
0
        *data++ = (u_char) intsize;
2172
0
        *datalength = *datalength - 3;
2173
0
    } else {
2174
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2175
0
        data = asn_build_header(data, datalength, type, intsize);
2176
0
        if (_asn_build_header_check
2177
0
            ("build uint64", data, *datalength, intsize))
2178
0
            return NULL;
2179
2180
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2181
0
    }
2182
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2183
0
    *datalength -= intsize;
2184
0
    if (add_null_byte == 1) {
2185
0
        *data++ = '\0';
2186
0
        intsize--;
2187
0
    }
2188
0
    while (intsize--) {
2189
0
        *data++ = value >> 56;
2190
0
        value <<= 8;
2191
0
    }
2192
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2193
0
    DEBUGIF("dumpv_send") {
2194
0
        char            i64buf[I64CHARSZ + 1];
2195
0
        printU64(i64buf, cp);
2196
0
        DEBUGMSG(("dumpv_send", "%s", i64buf));
2197
0
    }
2198
0
    return data;
2199
0
}
2200
2201
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
2202
2203
2204
/**
2205
 * @internal
2206
 * asn_parse_signed_int64 - pulls a 64 bit signed long out of an ASN int
2207
 * type.
2208
 *
2209
 *  On entry, datalength is input as the number of valid bytes following
2210
 *   "data".  On exit, it is returned as the number of valid bytes
2211
 *   following the end of this object.
2212
 *
2213
 *  Returns a pointer to the first byte past the end
2214
 *   of this object (i.e. the start of the next object).
2215
 *  Returns NULL on any error.
2216
 
2217
 * @param data         IN - pointer to start of object
2218
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2219
 * @param type         OUT - asn type of object
2220
 * @param cp           IN/OUT - pointer to counter struct
2221
 * @param countersize  IN - size of output buffer
2222
 * @return  Returns a pointer to the first byte past the end
2223
 *          of this object (i.e. the start of the next object).
2224
 *          Returns NULL on any error.
2225
 */
2226
2227
u_char         *
2228
asn_parse_signed_int64(u_char * data,
2229
                       size_t * datalength,
2230
                       u_char * type,
2231
                       struct counter64 *cp, size_t countersize)
2232
108
{
2233
108
    static const char *errpre = "parse int64";
2234
108
    const int       int64sizelimit = (4 * 2) + 1;
2235
108
    char            ebuf[128];
2236
108
    register u_char *bufp = data;
2237
108
    u_long          asn_length;
2238
108
    register u_int  low = 0, high = 0;
2239
2240
108
    if (countersize != sizeof(struct counter64)) {
2241
0
        _asn_size_err(errpre, countersize, sizeof(struct counter64));
2242
0
        return NULL;
2243
0
    }
2244
2245
108
    if (NULL == data || NULL == datalength || NULL == type || NULL == cp) {
2246
0
        ERROR_MSG("parse int64: NULL pointer");
2247
0
        return NULL;
2248
0
    }
2249
2250
    /** need at least 2 bytes to work with: type, length (which might be 0) */
2251
108
    if (*datalength < 2) {
2252
0
        _asn_short_err(errpre, *datalength, 2);
2253
0
        return NULL;
2254
0
    }
2255
2256
108
    *type = *bufp++;
2257
108
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2258
108
    if (NULL == bufp) {
2259
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2260
0
        return NULL;
2261
0
    }
2262
2263
    /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_I64 */
2264
108
    if (asn_length < 2) {
2265
4
        _asn_short_err(errpre, asn_length, 2);
2266
4
        return NULL;
2267
4
    }
2268
2269
104
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2270
104
    if ((*type == ASN_OPAQUE) &&
2271
104
        (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
2272
104
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_I64)) {
2273
        /*
2274
         * change type to Int64 
2275
         */
2276
102
        *type = *(bufp + 1);
2277
        /*
2278
         * value is encoded as special format 
2279
         */
2280
102
        *datalength = asn_length;
2281
102
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2282
102
        if (NULL == bufp) {
2283
0
            _asn_short_err("parse opaque int64", *datalength - 2, asn_length);
2284
0
            return NULL;
2285
0
        }
2286
102
    }
2287
    /*
2288
     * this should always have been true until snmp gets int64 PDU types 
2289
     */
2290
2
    else {
2291
2
        snprintf(ebuf, sizeof(ebuf),
2292
2
                "%s: wrong type: %d, len %d, buf bytes (%02X,%02X)",
2293
2
                errpre, *type, (int) asn_length, *bufp, *(bufp + 1));
2294
2
        ebuf[ sizeof(ebuf)-1 ] = 0;
2295
2
        ERROR_MSG(ebuf);
2296
2
        return NULL;
2297
2
    }
2298
102
    if (((int) asn_length > int64sizelimit) ||
2299
102
        (((int) asn_length == int64sizelimit) && *bufp != 0x00)) {
2300
8
        _asn_length_err(errpre, (size_t) asn_length, int64sizelimit);
2301
8
        return NULL;
2302
8
    }
2303
94
    *datalength -= (int) asn_length + (bufp - data);
2304
94
    if ((asn_length > 0) && (*bufp & 0x80)) {
2305
54
        low = 0xFFFFFFFFU;   /* first byte bit 1 means start the data with 1s */
2306
54
        high = 0xFFFFFF;
2307
54
    }
2308
2309
687
    while (asn_length--) {
2310
593
        high = ((0x00FFFFFF & high) << 8) | ((low & 0xFF000000U) >> 24);
2311
593
        low = ((low & 0x00FFFFFF) << 8) | *bufp++;
2312
593
    }
2313
2314
94
    CHECK_OVERFLOW_U(high,8);
2315
94
    CHECK_OVERFLOW_U(low,8);
2316
2317
94
    cp->low = low;
2318
94
    cp->high = high;
2319
2320
94
    DEBUGIF("dumpv_recv") {
2321
94
        char            i64buf[I64CHARSZ + 1];
2322
94
        printI64(i64buf, cp);
2323
94
        DEBUGMSG(("dumpv_recv", "Integer64: %s\n", i64buf));
2324
94
    }
2325
2326
94
    return bufp;
2327
102
}
2328
2329
2330
2331
/**
2332
 * @internal
2333
 * asn_build_signed_int64 - builds an ASN object containing a 64 bit integer.
2334
 *
2335
 *  On entry, datalength is input as the number of valid bytes following
2336
 *   "data".  On exit, it is returned as the number of valid bytes
2337
 *   following the end of this object.
2338
 *
2339
 *  Returns a pointer to the first byte past the end
2340
 *   of this object (i.e. the start of the next object).
2341
 *  Returns NULL on any error.
2342
 *
2343
 * @param data         IN - pointer to start of output buffer
2344
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2345
 * @param type         IN  - asn type of object
2346
 * @param cp           IN - pointer to counter struct
2347
 * @param countersize  IN - size of input buffer
2348
 * @return  Returns a pointer to the first byte past the end
2349
 *          of this object (i.e. the start of the next object).
2350
 *          Returns NULL on any error.
2351
 */
2352
u_char         *
2353
asn_build_signed_int64(u_char * data,
2354
                       size_t * datalength,
2355
                       u_char type,
2356
                       const struct counter64 *cp, size_t countersize)
2357
0
{
2358
    /*
2359
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
2360
     */
2361
2362
0
    register u_int  mask, mask2;
2363
0
    u_long          low;
2364
0
    long            high; /* MUST be signed because of CHECK_OVERFLOW_S(). */
2365
0
    size_t          intsize;
2366
0
    u_char         *initdatap = data;
2367
2368
0
    if (countersize != sizeof(struct counter64)) {
2369
0
        _asn_size_err("build int64", countersize,
2370
0
                      sizeof(struct counter64));
2371
0
        return NULL;
2372
0
    }
2373
0
    intsize = 8;
2374
0
    low = cp->low;
2375
0
    high = cp->high; /* unsigned to signed conversion */
2376
2377
0
    CHECK_OVERFLOW_S(high,9);
2378
0
    CHECK_OVERFLOW_U(low,9);
2379
2380
    /*
2381
     * Truncate "unnecessary" bytes off of the most significant end of this
2382
     * 2's complement integer.  There should be no sequence of 9
2383
     * consecutive 1's or 0's at the most significant end of the
2384
     * integer.
2385
     */
2386
0
    mask = 0xFF000000U;
2387
0
    mask2 = 0xFF800000U;
2388
0
    while ((((high & mask2) == 0) || ((high & mask2) == mask2))
2389
0
           && intsize > 1) {
2390
0
        intsize--;
2391
0
        high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
2392
0
        low = (low & 0x00ffffff) << 8;
2393
0
    }
2394
    /*
2395
     * until a real int64 gets incorperated into SNMP, we are going to
2396
     * encode it as an opaque instead.  First, we build the opaque
2397
     * header and then the int64 tag type we use to mark it as an
2398
     * int64 in the opaque string. 
2399
     */
2400
0
    data = asn_build_header(data, datalength, ASN_OPAQUE, intsize + 3);
2401
0
    if (_asn_build_header_check
2402
0
        ("build int64", data, *datalength, intsize + 3))
2403
0
        return NULL;
2404
2405
0
    *data++ = ASN_OPAQUE_TAG1;
2406
0
    *data++ = ASN_OPAQUE_I64;
2407
0
    *data++ = (u_char) intsize;
2408
0
    *datalength -= (3 + intsize);
2409
2410
0
    while (intsize--) {
2411
0
        *data++ = (u_char) (high >> 24);
2412
0
        high = ((high & 0x00ffffff) << 8) | ((low & mask) >> 24);
2413
0
        low = (low & 0x00ffffff) << 8;
2414
0
    }
2415
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2416
0
    DEBUGIF("dumpv_send") {
2417
0
        char            i64buf[I64CHARSZ + 1];
2418
0
        printU64(i64buf, cp);
2419
0
        DEBUGMSG(("dumpv_send", "%s\n", i64buf));
2420
0
    }
2421
0
    return data;
2422
0
}
2423
2424
2425
/**
2426
 * @internal
2427
 * asn_parse_float - pulls a single precision floating-point out of an opaque type.
2428
 *
2429
 *  On entry, datalength is input as the number of valid bytes following
2430
 *   "data".  On exit, it is returned as the number of valid bytes
2431
 *   following the end of this object.
2432
 *
2433
 *  Returns a pointer to the first byte past the end
2434
 *   of this object (i.e. the start of the next object).
2435
 *  Returns NULL on any error.
2436
 *
2437
 * @param data         IN - pointer to start of object
2438
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2439
 * @param type         OUT - asn type of object
2440
 * @param floatp       IN/OUT - pointer to float
2441
 * @param floatsize    IN - size of output buffer
2442
 * @return  Returns a pointer to the first byte past the end
2443
 *          of this object (i.e. the start of the next object).
2444
 *          Returns NULL on any error.
2445
 */
2446
u_char         *
2447
asn_parse_float(u_char * data,
2448
                size_t * datalength,
2449
                u_char * type, float *floatp, size_t floatsize)
2450
16
{
2451
16
    static const char *errpre = "parse float";
2452
16
    register u_char *bufp = data;
2453
16
    u_long          asn_length;
2454
16
    union {
2455
16
        float           floatVal;
2456
16
        long            longVal;
2457
16
        u_char          c[sizeof(float)];
2458
16
    } fu;
2459
2460
16
    if (floatsize != sizeof(float)) {
2461
0
        _asn_size_err("parse float", floatsize, sizeof(float));
2462
0
        return NULL;
2463
0
    }
2464
2465
16
    if (NULL == data || NULL == datalength || NULL == type || NULL == floatp) {
2466
0
        ERROR_MSG("parse float: NULL pointer");
2467
0
        return NULL;
2468
0
    }
2469
2470
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
2471
16
    if (*datalength < 2) {
2472
0
        _asn_short_err(errpre, *datalength, 2);
2473
0
        return NULL;
2474
0
    }
2475
2476
16
    *type = *bufp++;
2477
16
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2478
16
    if (NULL == bufp) {
2479
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2480
0
        return NULL;
2481
0
    }
2482
2483
16
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2484
    /*
2485
     * the float is encoded as an opaque 
2486
     */
2487
16
    if ((*type == ASN_OPAQUE) &&
2488
16
        (asn_length == ASN_OPAQUE_FLOAT_BER_LEN) &&
2489
16
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_FLOAT)) {
2490
2491
        /*
2492
         * value is encoded as special format 
2493
         */
2494
1
        *datalength = asn_length;
2495
1
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2496
1
        if (NULL == bufp) {
2497
0
            _asn_short_err("parse opaque float", *datalength - 2, asn_length);
2498
0
            return NULL;
2499
0
        }
2500
        /*
2501
         * change type to Float 
2502
         */
2503
1
        *type = ASN_OPAQUE_FLOAT;
2504
1
    }
2505
2506
16
    if (*type != ASN_OPAQUE_FLOAT) {
2507
5
        _asn_type_err(errpre, *type);
2508
5
        return NULL;
2509
5
    }
2510
2511
11
    if (asn_length != sizeof(float)) {
2512
8
        _asn_size_err("parse seq float", asn_length, sizeof(float));
2513
8
        return NULL;
2514
8
    }
2515
2516
3
    *datalength -= (int) asn_length + (bufp - data);
2517
3
    memcpy(&fu.c[0], bufp, asn_length);
2518
2519
    /*
2520
     * correct for endian differences 
2521
     */
2522
3
    fu.longVal = ntohl(fu.longVal);
2523
2524
3
    *floatp = fu.floatVal;
2525
2526
3
    DEBUGMSG(("dumpv_recv", "Opaque float: %f\n", *floatp));
2527
3
    return bufp;
2528
11
}
2529
2530
/**
2531
 * @internal
2532
 * asn_build_float - builds an ASN object containing a single precision floating-point
2533
 *                    number in an Opaque value.
2534
 *
2535
 *  On entry, datalength is input as the number of valid bytes following
2536
 *   "data".  On exit, it is returned as the number of valid bytes
2537
 *   following the end of this object.
2538
 *
2539
 *  Returns a pointer to the first byte past the end
2540
 *   of this object (i.e. the start of the next object).
2541
 *  Returns NULL on any error.
2542
 *
2543
 * @param data         IN - pointer to start of object
2544
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2545
 * @param type         IN - asn type of object
2546
 * @param floatp       IN - pointer to float
2547
 * @param floatsize    IN - size of input buffer
2548
 * @return  Returns a pointer to the first byte past the end
2549
 *          of this object (i.e. the start of the next object).
2550
 *          Returns NULL on any error.
2551
2552
 */
2553
u_char         *
2554
asn_build_float(u_char * data,
2555
                size_t * datalength,
2556
                u_char type, const float *floatp, size_t floatsize)
2557
0
{
2558
0
    union {
2559
0
        float           floatVal;
2560
0
        int             intVal;
2561
0
        u_char          c[sizeof(float)];
2562
0
    } fu;
2563
0
    u_char         *initdatap = data;
2564
2565
0
    if (floatsize != sizeof(float)) {
2566
0
        _asn_size_err("build float", floatsize, sizeof(float));
2567
0
        return NULL;
2568
0
    }
2569
    /*
2570
     * encode the float as an opaque 
2571
     */
2572
    /*
2573
     * turn into Opaque holding special tagged value 
2574
     */
2575
2576
    /*
2577
     * put the tag and length for the Opaque wrapper 
2578
     */
2579
0
    data = asn_build_header(data, datalength, ASN_OPAQUE, floatsize + 3);
2580
0
    if (_asn_build_header_check
2581
0
        ("build float", data, *datalength, (floatsize + 3)))
2582
0
        return NULL;
2583
2584
    /*
2585
     * put the special tag and length 
2586
     */
2587
0
    *data++ = ASN_OPAQUE_TAG1;
2588
0
    *data++ = ASN_OPAQUE_FLOAT;
2589
0
    *data++ = (u_char) floatsize;
2590
0
    *datalength = *datalength - 3;
2591
2592
0
    fu.floatVal = *floatp;
2593
    /*
2594
     * correct for endian differences 
2595
     */
2596
0
    fu.intVal = htonl(fu.intVal);
2597
2598
0
    *datalength -= floatsize;
2599
0
    memcpy(data, &fu.c[0], floatsize);
2600
2601
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2602
0
    DEBUGMSG(("dumpv_send", "Opaque float: %f\n", *floatp));
2603
0
    data += floatsize;
2604
0
    return data;
2605
0
}
2606
2607
2608
/**
2609
 * @internal
2610
 * asn_parse_double - pulls a double out of an opaque type.
2611
 *
2612
 *  On entry, datalength is input as the number of valid bytes following
2613
 *   "data".  On exit, it is returned as the number of valid bytes
2614
 *   following the end of this object.
2615
 *
2616
 *  Returns a pointer to the first byte past the end
2617
 *   of this object (i.e. the start of the next object).
2618
 *  Returns NULL on any error.
2619
 *
2620
 * @param data         IN - pointer to start of object
2621
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2622
 * @param type         OUT - asn type of object
2623
 * @param doublep       IN/OUT - pointer to double
2624
 * @param doublesize    IN - size of output buffer
2625
 * @return  Returns a pointer to the first byte past the end
2626
 *          of this object (i.e. the start of the next object).
2627
 *          Returns NULL on any error.
2628
 */
2629
u_char         *
2630
asn_parse_double(u_char * data,
2631
                 size_t * datalength,
2632
                 u_char * type, double *doublep, size_t doublesize)
2633
14
{
2634
14
    static const char *errpre = "parse double";
2635
14
    register u_char *bufp = data;
2636
14
    u_long          asn_length;
2637
14
    long            tmp;
2638
14
    union {
2639
14
        double          doubleVal;
2640
14
        int             intVal[2];
2641
14
        u_char          c[sizeof(double)];
2642
14
    } fu;
2643
2644
2645
14
    if (doublesize != sizeof(double)) {
2646
0
        _asn_size_err("parse double", doublesize, sizeof(double));
2647
0
        return NULL;
2648
0
    }
2649
2650
14
    if (NULL == data || NULL == datalength || NULL == type || NULL == doublep) {
2651
0
        ERROR_MSG("parse double: NULL pointer");
2652
0
        return NULL;
2653
0
    }
2654
2655
    /** need at least 2 bytes to work with: type, length (which might be 0)  */
2656
14
    if (*datalength < 2) {
2657
0
        _asn_short_err(errpre, *datalength, 2);
2658
0
        return NULL;
2659
0
    }
2660
2661
14
    *type = *bufp++;
2662
14
    bufp = asn_parse_nlength(bufp, *datalength - 1, &asn_length);
2663
14
    if (NULL == bufp) {
2664
0
        _asn_short_err(errpre, *datalength - 1, asn_length);
2665
0
        return NULL;
2666
0
    }
2667
2668
14
    DEBUGDUMPSETUP("recv", data, bufp - data + asn_length);
2669
    /*
2670
     * the double is encoded as an opaque 
2671
     */
2672
    /** need at least 2 bytes: ASN_OPAQUE_TAG1 and ASN_OPAQUE_DOUBLE */
2673
14
    if ((*type == ASN_OPAQUE) && (asn_length < 2)) {
2674
0
        _asn_short_err(errpre, asn_length, 2);
2675
0
        return NULL;
2676
0
    }
2677
14
    if ((*type == ASN_OPAQUE) &&
2678
14
        (asn_length == ASN_OPAQUE_DOUBLE_BER_LEN) &&
2679
14
        (*bufp == ASN_OPAQUE_TAG1) && (*(bufp + 1) == ASN_OPAQUE_DOUBLE)) {
2680
2681
        /*
2682
         * value is encoded as special format 
2683
         */
2684
1
        *datalength = asn_length;
2685
1
        bufp = asn_parse_nlength(bufp+2, *datalength - 2, &asn_length);
2686
1
        if (NULL == bufp) {
2687
0
            _asn_short_err("parse opaque double", *datalength - 2, asn_length);
2688
0
            return NULL;
2689
0
        }
2690
2691
        /*
2692
         * change type to Double 
2693
         */
2694
1
        *type = ASN_OPAQUE_DOUBLE;
2695
1
    }
2696
2697
14
    if (*type != ASN_OPAQUE_DOUBLE) {
2698
5
        _asn_type_err(errpre, *type);
2699
5
        return NULL;
2700
5
    }
2701
2702
9
    if (asn_length != sizeof(double)) {
2703
8
        _asn_size_err("parse seq double", asn_length, sizeof(double));
2704
8
        return NULL;
2705
8
    }
2706
1
    *datalength -= (int) asn_length + (bufp - data);
2707
1
    memcpy(&fu.c[0], bufp, asn_length);
2708
2709
    /*
2710
     * correct for endian differences 
2711
     */
2712
2713
1
    tmp = ntohl(fu.intVal[0]);
2714
1
    fu.intVal[0] = ntohl(fu.intVal[1]);
2715
1
    fu.intVal[1] = tmp;
2716
2717
1
    *doublep = fu.doubleVal;
2718
1
    DEBUGMSG(("dumpv_recv", "  Opaque Double:\t%f\n", *doublep));
2719
2720
1
    return bufp;
2721
9
}
2722
2723
2724
/**
2725
 * @internal
2726
 * asn_build_double - builds an ASN object containing a double
2727
 *                    number in an Opaque value.
2728
 *
2729
 *  On entry, datalength is input as the number of valid bytes following
2730
 *   "data".  On exit, it is returned as the number of valid bytes
2731
 *   following the end of this object.
2732
 *
2733
 *  Returns a pointer to the first byte past the end
2734
 *   of this object (i.e. the start of the next object).
2735
 *  Returns NULL on any error.
2736
 *
2737
 * @param data         IN - pointer to start of object
2738
 * @param datalength   IN/OUT - number of valid bytes left in buffer
2739
 * @param type         IN - asn type of object
2740
 * @param doublep      IN - pointer to double
2741
 * @param doublesize   IN - size of input buffer
2742
 * @return  Returns a pointer to the first byte past the end
2743
 *          of this object (i.e. the start of the next object).
2744
 *          Returns NULL on any error.
2745
 */
2746
u_char         *
2747
asn_build_double(u_char * data,
2748
                 size_t * datalength,
2749
                 u_char type, const double *doublep, size_t doublesize)
2750
0
{
2751
0
    long            tmp;
2752
0
    union {
2753
0
        double          doubleVal;
2754
0
        int             intVal[2];
2755
0
        u_char          c[sizeof(double)];
2756
0
    } fu;
2757
0
    u_char         *initdatap = data;
2758
2759
0
    if (doublesize != sizeof(double)) {
2760
0
        _asn_size_err("build double", doublesize, sizeof(double));
2761
0
        return NULL;
2762
0
    }
2763
2764
    /*
2765
     * encode the double as an opaque 
2766
     */
2767
    /*
2768
     * turn into Opaque holding special tagged value 
2769
     */
2770
2771
    /*
2772
     * put the tag and length for the Opaque wrapper 
2773
     */
2774
0
    data = asn_build_header(data, datalength, ASN_OPAQUE, doublesize + 3);
2775
0
    if (_asn_build_header_check
2776
0
        ("build double", data, *datalength, doublesize + 3))
2777
0
        return NULL;
2778
2779
    /*
2780
     * put the special tag and length 
2781
     */
2782
0
    *data++ = ASN_OPAQUE_TAG1;
2783
0
    *data++ = ASN_OPAQUE_DOUBLE;
2784
0
    *data++ = (u_char) doublesize;
2785
0
    *datalength = *datalength - 3;
2786
2787
0
    fu.doubleVal = *doublep;
2788
    /*
2789
     * correct for endian differences 
2790
     */
2791
0
    tmp = htonl(fu.intVal[0]);
2792
0
    fu.intVal[0] = htonl(fu.intVal[1]);
2793
0
    fu.intVal[1] = tmp;
2794
0
    *datalength -= doublesize;
2795
0
    memcpy(data, &fu.c[0], doublesize);
2796
2797
0
    data += doublesize;
2798
0
    DEBUGDUMPSETUP("send", initdatap, data - initdatap);
2799
0
    DEBUGMSG(("dumpv_send", "  Opaque double: %f\n", *doublep));
2800
0
    return data;
2801
0
}
2802
2803
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
2804
2805
2806
/**
2807
 * @internal
2808
 * This function increases the size of the buffer pointed to by *pkt, which
2809
 * is initially of size *pkt_len.  Contents are preserved **AT THE TOP END OF 
2810
 * THE BUFFER** (hence making this function useful for reverse encoding).
2811
 * You can change the reallocation scheme, but you **MUST** guarantee to
2812
 * allocate **AT LEAST** one extra byte.  If memory cannot be reallocated,
2813
 * then return 0; otherwise return 1.   
2814
 * 
2815
 * @param pkt     buffer to increase
2816
 * @param pkt_len initial buffer size
2817
 * 
2818
 * @return 1 on success 0 on error (memory cannot be reallocated)
2819
 */
2820
int
2821
asn_realloc(u_char ** pkt, size_t * pkt_len)
2822
0
{
2823
0
    if (pkt != NULL && pkt_len != NULL) {
2824
0
        size_t          old_pkt_len = *pkt_len;
2825
2826
0
        DEBUGMSGTL(("asn_realloc", " old_pkt %8p, old_pkt_len %" NETSNMP_PRIz
2827
0
                    "u\n", *pkt, old_pkt_len));
2828
2829
0
        if (snmp_realloc(pkt, pkt_len)) {
2830
0
            DEBUGMSGTL(("asn_realloc", " new_pkt %8p, new_pkt_len %"
2831
0
                        NETSNMP_PRIz "u\n", *pkt, *pkt_len));
2832
0
            DEBUGMSGTL(("asn_realloc", " memmove(%8p + %08" NETSNMP_PRIz
2833
0
                        "x, %8p, %08" NETSNMP_PRIz "x)\n", *pkt,
2834
0
                        *pkt_len - old_pkt_len, *pkt, old_pkt_len));
2835
0
            memmove(*pkt + (*pkt_len - old_pkt_len), *pkt, old_pkt_len);
2836
0
            memset(*pkt, ' ', *pkt_len - old_pkt_len);
2837
0
            return 1;
2838
0
        } else {
2839
0
            DEBUGMSG(("asn_realloc", " CANNOT REALLOC()\n"));
2840
0
        }
2841
0
    }
2842
0
    return 0;
2843
0
}
2844
2845
#ifdef NETSNMP_USE_REVERSE_ASNENCODING
2846
2847
/**
2848
 * @internal
2849
 * reverse  builds an ASN header for a length with
2850
 * length specified.
2851
 * 
2852
 * @param pkt     IN/OUT address of the begining of the buffer.
2853
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
2854
 * @param offset  IN/OUT offset to the start of the buffer where to write
2855
 * @param r       IN if not zero reallocate the buffer to fit the 
2856
 *                needed size.
2857
 * @param length  IN - length of object
2858
 *
2859
 * @return 1 on success, 0 on error
2860
 */
2861
int
2862
asn_realloc_rbuild_length(u_char ** pkt, size_t * pkt_len,
2863
                          size_t * offset, int r, size_t length)
2864
0
{
2865
0
    static const char *errpre = "build length";
2866
0
    char            ebuf[128];
2867
0
    int             tmp_int;
2868
0
    size_t          start_offset = *offset;
2869
2870
0
    if (length <= 0x7f) {
2871
0
        if (((*pkt_len - *offset) < 1)
2872
0
            && !(r && asn_realloc(pkt, pkt_len))) {
2873
0
            snprintf(ebuf, sizeof(ebuf),
2874
0
                    "%s: bad length < 1 :%ld, %lu", errpre,
2875
0
                    (long)(*pkt_len - *offset), (unsigned long)length);
2876
0
            ebuf[ sizeof(ebuf)-1 ] = 0;
2877
0
            ERROR_MSG(ebuf);
2878
0
            return 0;
2879
0
        }
2880
0
        *(*pkt + *pkt_len - (++*offset)) = length;
2881
0
    } else {
2882
0
        while (length > 0xff) {
2883
0
            if (((*pkt_len - *offset) < 1)
2884
0
                && !(r && asn_realloc(pkt, pkt_len))) {
2885
0
                snprintf(ebuf, sizeof(ebuf),
2886
0
                        "%s: bad length < 1 :%ld, %lu", errpre,
2887
0
                        (long)(*pkt_len - *offset), (unsigned long)length);
2888
0
                ebuf[ sizeof(ebuf)-1 ] = 0;
2889
0
                ERROR_MSG(ebuf);
2890
0
                return 0;
2891
0
            }
2892
0
            *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
2893
0
            length >>= 8;
2894
0
        }
2895
2896
0
        while ((*pkt_len - *offset) < 2) {
2897
0
            if (!(r && asn_realloc(pkt, pkt_len))) {
2898
0
                snprintf(ebuf, sizeof(ebuf),
2899
0
                        "%s: bad length < 1 :%ld, %lu", errpre,
2900
0
                        (long)(*pkt_len - *offset), (unsigned long)length);
2901
0
                ebuf[ sizeof(ebuf)-1 ] = 0;
2902
0
                ERROR_MSG(ebuf);
2903
0
                return 0;
2904
0
            }
2905
0
        }
2906
2907
0
        *(*pkt + *pkt_len - (++*offset)) = length & 0xff;
2908
0
        tmp_int = *offset - start_offset;
2909
0
        *(*pkt + *pkt_len - (++*offset)) = tmp_int | 0x80;
2910
0
    }
2911
2912
0
    return 1;
2913
0
}
2914
2915
/**
2916
 * @internal
2917
 * builds an ASN header for an object with the ID and
2918
 * length specified.
2919
 *
2920
 * @see asn_build_header
2921
 * 
2922
 * @param pkt     IN/OUT address of the begining of the buffer.
2923
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
2924
 * @param offset  IN/OUT offset to the start of the buffer where to write
2925
 * @param r       IN if not zero reallocate the buffer to fit the 
2926
 *                needed size.
2927
 * @param type   IN - type of object
2928
 * @param length   IN - length of object
2929
 *
2930
 * @return 1 on success, 0 on error
2931
 */
2932
int
2933
asn_realloc_rbuild_header(u_char ** pkt, size_t * pkt_len,
2934
                          size_t * offset, int r,
2935
                          u_char type, size_t length)
2936
0
{
2937
0
    char            ebuf[128];
2938
2939
0
    if (asn_realloc_rbuild_length(pkt, pkt_len, offset, r, length)) {
2940
0
        if (((*pkt_len - *offset) < 1)
2941
0
            && !(r && asn_realloc(pkt, pkt_len))) {
2942
0
            snprintf(ebuf, sizeof(ebuf),
2943
0
                    "bad header length < 1 :%ld, %lu",
2944
0
                    (long)(*pkt_len - *offset), (unsigned long)length);
2945
0
            ebuf[ sizeof(ebuf)-1 ] = 0;
2946
0
            ERROR_MSG(ebuf);
2947
0
            return 0;
2948
0
        }
2949
0
        *(*pkt + *pkt_len - (++*offset)) = type;
2950
0
        return 1;
2951
0
    }
2952
0
    return 0;
2953
0
}
2954
2955
/**
2956
 * @internal
2957
 * builds an ASN object containing an int.
2958
 *
2959
 * @see asn_build_int
2960
 * 
2961
 * @param pkt     IN/OUT address of the begining of the buffer.
2962
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
2963
 * @param offset  IN/OUT offset to the start of the buffer where to write
2964
 * @param r       IN if not zero reallocate the buffer to fit the 
2965
 *                needed size.
2966
 * @param type    IN - type of object
2967
 * @param intp    IN - pointer to start of long integer
2968
 * @param intsize IN - size of input buffer
2969
 *
2970
 * @return 1 on success, 0 on error
2971
 */
2972
int
2973
asn_realloc_rbuild_int(u_char ** pkt, size_t * pkt_len,
2974
                       size_t * offset, int r,
2975
                       u_char type, const long *intp, size_t intsize)
2976
0
{
2977
0
    static const char *errpre = "build int";
2978
0
    register long   integer = *intp;
2979
0
    int             testvalue;
2980
0
    size_t          start_offset = *offset;
2981
2982
0
    if (intsize != sizeof(long)) {
2983
0
        _asn_size_err(errpre, intsize, sizeof(long));
2984
0
        return 0;
2985
0
    }
2986
2987
0
    CHECK_OVERFLOW_S(integer,10);
2988
0
    testvalue = (integer < 0) ? -1 : 0;
2989
2990
0
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
2991
0
        return 0;
2992
0
    }
2993
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
2994
0
    integer >>= 8;
2995
2996
0
    while (integer != testvalue) {
2997
0
        if (((*pkt_len - *offset) < 1)
2998
0
            && !(r && asn_realloc(pkt, pkt_len))) {
2999
0
            return 0;
3000
0
        }
3001
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3002
0
        integer >>= 8;
3003
0
    }
3004
3005
0
    if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) {
3006
        /*
3007
         * Make sure left most bit is representational of the rest of the bits
3008
         * that aren't encoded.  
3009
         */
3010
0
        if (((*pkt_len - *offset) < 1)
3011
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3012
0
            return 0;
3013
0
        }
3014
0
        *(*pkt + *pkt_len - (++*offset)) = testvalue & 0xff;
3015
0
    }
3016
3017
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3018
0
                                  (*offset - start_offset))) {
3019
0
        if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
3020
0
                                            (*offset - start_offset))) {
3021
0
            return 0;
3022
0
        } else {
3023
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3024
0
                           (*offset - start_offset));
3025
0
            DEBUGMSG(("dumpv_send", "  Integer:\t%ld (0x%.2lX)\n", *intp,
3026
0
                      *intp));
3027
0
            return 1;
3028
0
        }
3029
0
    }
3030
3031
0
    return 0;
3032
0
}
3033
3034
/**
3035
 * @internal
3036
 * builds an ASN object containing an string.
3037
 *
3038
 * @see asn_build_string 
3039
 * 
3040
 * @param pkt     IN/OUT address of the begining of the buffer.
3041
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3042
 * @param offset  IN/OUT offset to the start of the buffer where to write
3043
 * @param r       IN if not zero reallocate the buffer to fit the 
3044
 *                needed size.
3045
 * @param type    IN - type of object
3046
 * @param string    IN - pointer to start of the string
3047
 * @param strlength IN - size of input buffer
3048
 *
3049
 * @return 1 on success, 0 on error
3050
 */
3051
3052
int
3053
asn_realloc_rbuild_string(u_char ** pkt, size_t * pkt_len,
3054
                          size_t * offset, int r,
3055
                          u_char type,
3056
                          const u_char * str, size_t strlength)
3057
0
{
3058
0
    static const char *errpre = "build string";
3059
0
    size_t          start_offset = *offset;
3060
3061
0
    while ((*pkt_len - *offset) < strlength) {
3062
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3063
0
            return 0;
3064
0
        }
3065
0
    }
3066
3067
0
    *offset += strlength;
3068
0
    if (str)
3069
0
        memcpy(*pkt + *pkt_len - *offset, str, strlength);
3070
3071
0
    if (asn_realloc_rbuild_header
3072
0
        (pkt, pkt_len, offset, r, type, strlength)) {
3073
0
        if (_asn_realloc_build_header_check
3074
0
            (errpre, pkt, pkt_len, strlength)) {
3075
0
            return 0;
3076
0
        } else {
3077
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3078
0
                           *offset - start_offset);
3079
0
            DEBUGIF("dumpv_send") {
3080
0
                if (strlength == 0) {
3081
0
                    DEBUGMSG(("dumpv_send", "  String: [NULL]\n"));
3082
0
                } else {
3083
0
                    u_char         *buf = (u_char *) malloc(2 * strlength);
3084
0
                    size_t          l =
3085
0
                        (buf != NULL) ? (2 * strlength) : 0, ol = 0;
3086
3087
0
                    if (sprint_realloc_asciistring
3088
0
                        (&buf, &l, &ol, 1, str, strlength)) {
3089
0
                        DEBUGMSG(("dumpv_send", "  String:\t%s\n", buf));
3090
0
                    } else {
3091
0
                        if (buf == NULL) {
3092
0
                            DEBUGMSG(("dumpv_send",
3093
0
                                      "  String:\t[TRUNCATED]\n"));
3094
0
                        } else {
3095
0
                            DEBUGMSG(("dumpv_send",
3096
0
                                      "  String:\t%s [TRUNCATED]\n", buf));
3097
0
                        }
3098
0
                    }
3099
0
                    if (buf != NULL) {
3100
0
                        free(buf);
3101
0
                    }
3102
0
                }
3103
0
            }
3104
0
        }
3105
0
        return 1;
3106
0
    }
3107
3108
0
    return 0;
3109
0
}
3110
3111
/**
3112
 * @internal
3113
 * builds an ASN object containing an unsigned int.
3114
 *
3115
 * @see asn_build_unsigned_int
3116
 * 
3117
 * @param pkt     IN/OUT address of the begining of the buffer.
3118
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3119
 * @param offset  IN/OUT offset to the start of the buffer where to write
3120
 * @param r       IN if not zero reallocate the buffer to fit the 
3121
 *                needed size.
3122
 * @param type    IN - type of object
3123
 * @param intp    IN - pointer to start of unsigned int
3124
 * @param intsize IN - size of input buffer
3125
 *
3126
 * @return 1 on success, 0 on error
3127
 */
3128
int
3129
asn_realloc_rbuild_unsigned_int(u_char ** pkt, size_t * pkt_len,
3130
                                size_t * offset, int r,
3131
                            u_char type, const u_long * intp, size_t intsize)
3132
0
{
3133
0
    static const char *errpre = "build uint";
3134
0
    register u_long integer = *intp;
3135
0
    size_t          start_offset = *offset;
3136
3137
0
    if (intsize != sizeof(unsigned long)) {
3138
0
        _asn_size_err(errpre, intsize, sizeof(unsigned long));
3139
0
        return 0;
3140
0
    }
3141
3142
0
    CHECK_OVERFLOW_U(integer,11);
3143
3144
0
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3145
0
        return 0;
3146
0
    }
3147
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3148
0
    integer >>= 8;
3149
3150
0
    while (integer != 0) {
3151
0
        if (((*pkt_len - *offset) < 1)
3152
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3153
0
            return 0;
3154
0
        }
3155
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) integer;
3156
0
        integer >>= 8;
3157
0
    }
3158
3159
0
    if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
3160
        /*
3161
         * Make sure left most bit is representational of the rest of the bits
3162
         * that aren't encoded.  
3163
         */
3164
0
        if (((*pkt_len - *offset) < 1)
3165
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3166
0
            return 0;
3167
0
        }
3168
0
        *(*pkt + *pkt_len - (++*offset)) = 0;
3169
0
    }
3170
3171
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3172
0
                                  (*offset - start_offset))) {
3173
0
        if (_asn_realloc_build_header_check(errpre, pkt, pkt_len,
3174
0
                                            (*offset - start_offset))) {
3175
0
            return 0;
3176
0
        } else {
3177
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3178
0
                           (*offset - start_offset));
3179
0
            DEBUGMSG(("dumpv_send", "  UInteger:\t%lu (0x%.2lX)\n", *intp,
3180
0
                      *intp));
3181
0
            return 1;
3182
0
        }
3183
0
    }
3184
3185
0
    return 0;
3186
0
}
3187
3188
/**
3189
 * @internal
3190
 * builds an ASN object containing an sequence.
3191
 *
3192
 * @see asn_build_sequence
3193
 * 
3194
 * @param pkt     IN/OUT address of the begining of the buffer.
3195
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3196
 * @param offset  IN/OUT offset to the start of the buffer where to write
3197
 * @param r       IN if not zero reallocate the buffer to fit the 
3198
 *                needed size.
3199
 * @param type    IN - type of object
3200
 * @param length IN - length of object
3201
 *
3202
 * @return 1 on success, 0 on error
3203
 */
3204
3205
int
3206
asn_realloc_rbuild_sequence(u_char ** pkt, size_t * pkt_len,
3207
                            size_t * offset, int r,
3208
                            u_char type, size_t length)
3209
0
{
3210
0
    return asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type,
3211
0
                                     length);
3212
0
}
3213
3214
/**
3215
 * @internal
3216
 * Store a single byte while reverse encoding.
3217
 * @param pkt[in|out]     Start of the buffer.
3218
 * @param pkt_len[in|out] Size of the buffer in bytes.
3219
 * @param offset[in|out]  Offset from the end of the buffer where to write.
3220
 * @param r[in]           If not zero, increase the buffer size if needed.
3221
 * @param byte[in]        Data to store.
3222
 *
3223
 * @return 1 on success, 0 on error.
3224
 */
3225
static int store_byte(uint8_t **pkt, size_t *pkt_len, size_t *offset, int r,
3226
                      uint8_t byte)
3227
0
{
3228
0
    netsnmp_assert(*offset <= *pkt_len);
3229
0
    if (*offset >= *pkt_len && (!r || !asn_realloc(pkt, pkt_len)))
3230
0
        return 0;
3231
0
    netsnmp_assert(*offset < *pkt_len);
3232
0
    *(*pkt + *pkt_len - (++*offset)) = byte;
3233
0
    return 1;
3234
0
}
3235
3236
/**
3237
 * @internal
3238
 * Store 32 bits while reverse encoding.
3239
 * @param pkt[in|out]     Start of the buffer.
3240
 * @param pkt_len[in|out] Size of the buffer in bytes.
3241
 * @param offset[in|out]  Offset from the end of the buffer where to write.
3242
 * @param r[in]           If not zero, increase the buffer size if needed.
3243
 * @param subid[in]       Data to store.
3244
 *
3245
 * @return 1 on success, 0 on error.
3246
 */
3247
static int store_uint32(uint8_t **pkt, size_t *pkt_len, size_t *offset, int r,
3248
                        uint32_t subid)
3249
0
{
3250
0
    if (!store_byte(pkt, pkt_len, offset, r, subid & 0x7f))
3251
0
        return 0;
3252
3253
0
    for (subid >>= 7; subid; subid >>= 7)
3254
0
        if (!store_byte(pkt, pkt_len, offset, r, subid | 0x80))
3255
0
            return 0;
3256
3257
0
    return 1;
3258
0
}
3259
3260
/**
3261
 * @internal
3262
 * builds an ASN object containing an objid.
3263
 *
3264
 * @see asn_build_objid
3265
 * 
3266
 * @param pkt     IN/OUT address of the begining of the buffer.
3267
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3268
 * @param offset  IN/OUT offset to the start of the buffer where to write
3269
 * @param r       IN if not zero reallocate the buffer to fit the 
3270
 *                needed size.
3271
 * @param type    IN - type of object
3272
 * @param objid   IN - pointer to the object id
3273
 * @param objidlength  IN - length of the input 
3274
 *
3275
 * @return 1 on success, 0 on error
3276
 */
3277
3278
int
3279
asn_realloc_rbuild_objid(u_char ** pkt, size_t * pkt_len,
3280
                         size_t * offset, int r,
3281
                         u_char type,
3282
                         const oid * objid, size_t objidlength)
3283
0
{
3284
    /*
3285
     * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
3286
     * subidentifier ::= {leadingbyte}* lastbyte
3287
     * leadingbyte ::= 1 7bitvalue
3288
     * lastbyte ::= 0 7bitvalue
3289
     */
3290
0
    register size_t i;
3291
0
    register oid    tmpint;
3292
0
    size_t          start_offset = *offset;
3293
0
    const char     *errpre = "build objid";
3294
3295
    /*
3296
     * Check if there are at least 2 sub-identifiers.  
3297
     */
3298
0
    if (objidlength == 0) {
3299
        /*
3300
         * There are not, so make the OID have two sub-identifiers with value
3301
         * zero. Encode both sub-identifiers as a single byte.
3302
         */
3303
0
        if (!store_byte(pkt, pkt_len, offset, r, 0))
3304
0
            return 0;
3305
0
    } else if (objid[0] > 2) {
3306
0
        ERROR_MSG("build objid: bad first subidentifier");
3307
0
        return 0;
3308
0
    } else if (objidlength == 1) {
3309
        /*
3310
         * Encode the first value.  
3311
         */
3312
0
        if (!store_byte(pkt, pkt_len, offset, r, 40 * objid[0]))
3313
0
            return 0;
3314
0
    } else {
3315
0
        for (i = objidlength - 1; i >= 2; i--) {
3316
0
            tmpint = objid[i];
3317
0
            CHECK_OVERFLOW_U(tmpint, 12);
3318
0
            if (!store_uint32(pkt, pkt_len, offset, r, tmpint))
3319
0
                return 0;
3320
0
        }
3321
3322
        /*
3323
         * Combine the first two values.  
3324
         */
3325
0
        if (objid[1] > 40 && objid[0] < 2) {
3326
0
            ERROR_MSG("build objid: bad second subidentifier");
3327
0
            return 0;
3328
0
        }
3329
0
        if (!store_uint32(pkt, pkt_len, offset, r, objid[0] * 40 + objid[1]))
3330
0
            return 0;
3331
0
    }
3332
3333
0
    tmpint = *offset - start_offset;
3334
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, tmpint)) {
3335
0
        if (_asn_realloc_build_header_check(errpre, pkt, pkt_len, tmpint)) {
3336
0
            return 0;
3337
0
        } else {
3338
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), tmpint);
3339
0
            DEBUGMSG(("dumpv_send", "  ObjID: "));
3340
0
            DEBUGMSGOID(("dumpv_send", objid, objidlength));
3341
0
            DEBUGMSG(("dumpv_send", "\n"));
3342
0
            return 1;
3343
0
        }
3344
0
    }
3345
3346
0
    return 0;
3347
0
}
3348
3349
/**
3350
 * @internal
3351
 * builds an ASN object containing an null object.
3352
 *
3353
 * @see asn_build_null
3354
 * 
3355
 * @param pkt     IN/OUT address of the begining of the buffer.
3356
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3357
 * @param offset  IN/OUT offset to the start of the buffer where to write
3358
 * @param r       IN if not zero reallocate the buffer to fit the 
3359
 *                needed size.
3360
 * @param type    IN - type of object
3361
 *
3362
 * @return 1 on success, 0 on error
3363
 */
3364
3365
int
3366
asn_realloc_rbuild_null(u_char ** pkt, size_t * pkt_len,
3367
                        size_t * offset, int r, u_char type)
3368
0
{
3369
    /*
3370
     * ASN.1 null ::= 0x05 0x00
3371
     */
3372
0
    size_t          start_offset = *offset;
3373
3374
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r, type, 0)) {
3375
0
        DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3376
0
                       (*offset - start_offset));
3377
0
        DEBUGMSG(("dumpv_send", "  NULL\n"));
3378
0
        return 1;
3379
0
    } else {
3380
0
        return 0;
3381
0
    }
3382
0
}
3383
3384
/**
3385
 * @internal
3386
 * builds an ASN object containing an bitstring.
3387
 *
3388
 * @see asn_build_bitstring
3389
 * 
3390
 * @param pkt     IN/OUT address of the begining of the buffer.
3391
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3392
 * @param offset  IN/OUT offset to the start of the buffer where to write
3393
 * @param r       IN if not zero reallocate the buffer to fit the 
3394
 *                needed size.
3395
 * @param type    IN - type of object
3396
 * @param string   IN - pointer to the string
3397
 * @param strlength  IN - length of the input 
3398
 *
3399
 * @return 1 on success, 0 on error
3400
 */
3401
3402
int
3403
asn_realloc_rbuild_bitstring(u_char ** pkt, size_t * pkt_len,
3404
                             size_t * offset, int r,
3405
                             u_char type,
3406
                             const u_char * str, size_t strlength)
3407
0
{
3408
    /*
3409
     * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
3410
     */
3411
0
    static const char *errpre = "build bitstring";
3412
0
    size_t          start_offset = *offset;
3413
3414
0
    while ((*pkt_len - *offset) < strlength) {
3415
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3416
0
            return 0;
3417
0
        }
3418
0
    }
3419
3420
0
    *offset += strlength;
3421
0
    memcpy(*pkt + *pkt_len - *offset, str, strlength);
3422
3423
0
    if (asn_realloc_rbuild_header
3424
0
        (pkt, pkt_len, offset, r, type, strlength)) {
3425
0
        if (_asn_realloc_build_header_check
3426
0
            (errpre, pkt, pkt_len, strlength)) {
3427
0
            return 0;
3428
0
        } else {
3429
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3430
0
                           *offset - start_offset);
3431
0
            DEBUGIF("dumpv_send") {
3432
0
                if (strlength == 0) {
3433
0
                    DEBUGMSG(("dumpv_send", "  Bitstring: [NULL]\n"));
3434
0
                } else {
3435
0
                    u_char         *buf = (u_char *) malloc(2 * strlength);
3436
0
                    size_t          l =
3437
0
                        (buf != NULL) ? (2 * strlength) : 0, ol = 0;
3438
3439
0
                    if (sprint_realloc_asciistring
3440
0
                        (&buf, &l, &ol, 1, str, strlength)) {
3441
0
                        DEBUGMSG(("dumpv_send", "  Bitstring:\t%s\n",
3442
0
                                  buf));
3443
0
                    } else {
3444
0
                        if (buf == NULL) {
3445
0
                            DEBUGMSG(("dumpv_send",
3446
0
                                      "  Bitstring:\t[TRUNCATED]\n"));
3447
0
                        } else {
3448
0
                            DEBUGMSG(("dumpv_send",
3449
0
                                      "  Bitstring:\t%s [TRUNCATED]\n",
3450
0
                                      buf));
3451
0
                        }
3452
0
                    }
3453
0
                    if (buf != NULL) {
3454
0
                        free(buf);
3455
0
                    }
3456
0
                }
3457
0
            }
3458
0
        }
3459
0
        return 1;
3460
0
    }
3461
3462
0
    return 0;
3463
0
}
3464
3465
/**
3466
 * @internal
3467
 * builds an ASN object containing an unsigned int64.
3468
 *
3469
 * @see asn_build_unsigned_int64
3470
 * 
3471
 * @param pkt     IN/OUT address of the begining of the buffer.
3472
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3473
 * @param offset  IN/OUT offset to the start of the buffer where to write
3474
 * @param r       IN if not zero reallocate the buffer to fit the 
3475
 *                needed size.
3476
 * @param type    IN - type of object
3477
 * @param cp           IN - pointer to counter struct
3478
 * @param countersize  IN - size of input buffer
3479
 *
3480
 * @return 1 on success, 0 on error
3481
 */
3482
int
3483
asn_realloc_rbuild_unsigned_int64(u_char ** pkt, size_t * pkt_len,
3484
                                  size_t * offset, int r,
3485
                                  u_char type,
3486
                               const struct counter64 *cp, size_t countersize)
3487
0
{
3488
    /*
3489
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
3490
     */
3491
0
    register u_long low = cp->low, high = cp->high;
3492
0
    size_t          intsize, start_offset = *offset;
3493
0
    int             count;
3494
3495
0
    if (countersize != sizeof(struct counter64)) {
3496
0
        _asn_size_err("build uint64", countersize,
3497
0
                      sizeof(struct counter64));
3498
0
        return 0;
3499
0
    }
3500
3501
0
    CHECK_OVERFLOW_U(high,13);
3502
0
    CHECK_OVERFLOW_U(low,13);
3503
3504
    /*
3505
     * Encode the low 4 bytes first.  
3506
     */
3507
0
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3508
0
        return 0;
3509
0
    }
3510
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3511
0
    low >>= 8;
3512
0
    count = 1;
3513
3514
0
    while (low != 0) {
3515
0
        count++;
3516
0
        if (((*pkt_len - *offset) < 1)
3517
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3518
0
            return 0;
3519
0
        }
3520
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3521
0
        low >>= 8;
3522
0
    }
3523
3524
    /*
3525
     * Then the high byte if present.  
3526
     */
3527
0
    if (high) {
3528
        /*
3529
         * Do the rest of the low byte.  
3530
         */
3531
0
        for (; count < 4; count++) {
3532
0
            if (((*pkt_len - *offset) < 1)
3533
0
                && !(r && asn_realloc(pkt, pkt_len))) {
3534
0
                return 0;
3535
0
            }
3536
0
            *(*pkt + *pkt_len - (++*offset)) = 0;
3537
0
        }
3538
3539
        /*
3540
         * Do high byte.  
3541
         */
3542
0
        if (((*pkt_len - *offset) < 1)
3543
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3544
0
            return 0;
3545
0
        }
3546
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3547
0
        high >>= 8;
3548
3549
0
        while (high != 0) {
3550
0
            if (((*pkt_len - *offset) < 1)
3551
0
                && !(r && asn_realloc(pkt, pkt_len))) {
3552
0
                return 0;
3553
0
            }
3554
0
            *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3555
0
            high >>= 8;
3556
0
        }
3557
0
    }
3558
3559
0
    if ((*(*pkt + *pkt_len - *offset) & 0x80) != (0 & 0x80)) {
3560
        /*
3561
         * Make sure left most bit is representational of the rest of the bits
3562
         * that aren't encoded.  
3563
         */
3564
0
        if (((*pkt_len - *offset) < 1)
3565
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3566
0
            return 0;
3567
0
        }
3568
0
        *(*pkt + *pkt_len - (++*offset)) = 0;
3569
0
    }
3570
3571
0
    intsize = *offset - start_offset;
3572
3573
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3574
    /*
3575
     * Encode a Counter64 as an opaque (it also works in SNMPv1).  
3576
     */
3577
0
    if (type == ASN_OPAQUE_COUNTER64) {
3578
0
        while ((*pkt_len - *offset) < 5) {
3579
0
            if (!(r && asn_realloc(pkt, pkt_len))) {
3580
0
                return 0;
3581
0
            }
3582
0
        }
3583
3584
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3585
0
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_COUNTER64;
3586
0
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3587
3588
        /*
3589
         * Put the tag and length for the Opaque wrapper.  
3590
         */
3591
0
        if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3592
0
                                      ASN_OPAQUE, intsize + 3)) {
3593
0
            if (_asn_realloc_build_header_check
3594
0
                ("build counter u64", pkt, pkt_len, intsize + 3)) {
3595
0
                return 0;
3596
0
            }
3597
0
        } else {
3598
0
            return 0;
3599
0
        }
3600
0
    } else if (type == ASN_OPAQUE_U64) {
3601
        /*
3602
         * Encode the Unsigned int64 in an opaque.  
3603
         */
3604
0
        while ((*pkt_len - *offset) < 5) {
3605
0
            if (!(r && asn_realloc(pkt, pkt_len))) {
3606
0
                return 0;
3607
0
            }
3608
0
        }
3609
3610
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3611
0
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_U64;
3612
0
        *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3613
3614
        /*
3615
         * Put the tag and length for the Opaque wrapper.  
3616
         */
3617
0
        if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3618
0
                                      ASN_OPAQUE, intsize + 3)) {
3619
0
            if (_asn_realloc_build_header_check
3620
0
                ("build counter u64", pkt, pkt_len, intsize + 3)) {
3621
0
                return 0;
3622
0
            }
3623
0
        } else {
3624
0
            return 0;
3625
0
        }
3626
0
    } else {
3627
3628
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3629
0
        if (asn_realloc_rbuild_header
3630
0
            (pkt, pkt_len, offset, r, type, intsize)) {
3631
0
            if (_asn_realloc_build_header_check
3632
0
                ("build uint64", pkt, pkt_len, intsize)) {
3633
0
                return 0;
3634
0
            }
3635
0
        } else {
3636
0
            return 0;
3637
0
        }
3638
0
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3639
0
    }
3640
0
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3641
3642
0
    DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
3643
0
    DEBUGMSG(("dumpv_send", "  U64:\t%lu %lu\n", cp->high, cp->low));
3644
0
    return 1;
3645
0
}
3646
3647
#ifdef NETSNMP_WITH_OPAQUE_SPECIAL_TYPES
3648
3649
3650
/**
3651
 * @internal
3652
 * builds an ASN object containing an signed int64.
3653
 *
3654
 * @see asn_build_signed_int64
3655
 * 
3656
 * @param pkt     IN/OUT address of the begining of the buffer.
3657
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3658
 * @param offset  IN/OUT offset to the start of the buffer where to write
3659
 * @param r       IN if not zero reallocate the buffer to fit the 
3660
 *                needed size.
3661
 * @param type    IN - type of object
3662
 * @param cp           IN - pointer to counter struct
3663
 * @param countersize  IN - size of input buffer
3664
 *
3665
 * @return 1 on success, 0 on error
3666
 */
3667
int
3668
asn_realloc_rbuild_signed_int64(u_char ** pkt, size_t * pkt_len,
3669
                                size_t * offset, int r,
3670
                                u_char type,
3671
                                const struct counter64 *cp, size_t countersize)
3672
0
{
3673
    /*
3674
     * ASN.1 integer ::= 0x02 asnlength byte {byte}*
3675
     */
3676
0
    register int32_t low = cp->low, high = cp->high;
3677
0
    size_t           intsize, start_offset = *offset;
3678
0
    int              count;
3679
0
    int32_t          testvalue = (high & 0x80000000) ? -1 : 0;
3680
3681
0
    if (countersize != sizeof(struct counter64)) {
3682
0
        _asn_size_err("build uint64", countersize,
3683
0
                      sizeof(struct counter64));
3684
0
        return 0;
3685
0
    }
3686
3687
    /*
3688
     * Encode the low 4 bytes first.  
3689
     */
3690
0
    if (((*pkt_len - *offset) < 1) && !(r && asn_realloc(pkt, pkt_len))) {
3691
0
        return 0;
3692
0
    }
3693
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3694
0
    low >>= 8;
3695
0
    count = 1;
3696
3697
0
    while ((int) low != testvalue && count < 4) {
3698
0
        count++;
3699
0
        if (((*pkt_len - *offset) < 1)
3700
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3701
0
            return 0;
3702
0
        }
3703
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) low;
3704
0
        low >>= 8;
3705
0
    }
3706
3707
    /*
3708
     * Then the high byte if present.  
3709
     */
3710
0
    if (high != testvalue) {
3711
        /*
3712
         * Do the rest of the low byte.  
3713
         */
3714
0
        for (; count < 4; count++) {
3715
0
            if (((*pkt_len - *offset) < 1)
3716
0
                && !(r && asn_realloc(pkt, pkt_len))) {
3717
0
                return 0;
3718
0
            }
3719
0
            *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
3720
0
        }
3721
3722
        /*
3723
         * Do high byte.  
3724
         */
3725
0
        if (((*pkt_len - *offset) < 1)
3726
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3727
0
            return 0;
3728
0
        }
3729
0
        *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3730
0
        high >>= 8;
3731
3732
0
        while ((int) high != testvalue) {
3733
0
            if (((*pkt_len - *offset) < 1)
3734
0
                && !(r && asn_realloc(pkt, pkt_len))) {
3735
0
                return 0;
3736
0
            }
3737
0
            *(*pkt + *pkt_len - (++*offset)) = (u_char) high;
3738
0
            high >>= 8;
3739
0
        }
3740
0
    }
3741
3742
0
    if ((*(*pkt + *pkt_len - *offset) & 0x80) != (testvalue & 0x80)) {
3743
        /*
3744
         * Make sure left most bit is representational of the rest of the bits
3745
         * that aren't encoded.  
3746
         */
3747
0
        if (((*pkt_len - *offset) < 1)
3748
0
            && !(r && asn_realloc(pkt, pkt_len))) {
3749
0
            return 0;
3750
0
        }
3751
0
        *(*pkt + *pkt_len - (++*offset)) = (testvalue == 0) ? 0 : 0xff;
3752
0
    }
3753
3754
0
    intsize = *offset - start_offset;
3755
3756
0
    while ((*pkt_len - *offset) < 5) {
3757
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3758
0
            return 0;
3759
0
        }
3760
0
    }
3761
3762
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) intsize;
3763
0
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_I64;
3764
0
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3765
3766
    /*
3767
     * Put the tag and length for the Opaque wrapper.  
3768
     */
3769
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3770
0
                                  ASN_OPAQUE, intsize + 3)) {
3771
0
        if (_asn_realloc_build_header_check
3772
0
            ("build counter u64", pkt, pkt_len, intsize + 3)) {
3773
0
            return 0;
3774
0
        }
3775
0
    } else {
3776
0
        return 0;
3777
0
    }
3778
3779
0
    DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset), intsize);
3780
0
    DEBUGMSG(("dumpv_send", "  UInt64:\t%lu %lu\n", cp->high, cp->low));
3781
0
    return 1;
3782
0
}
3783
3784
/**
3785
 * @internal
3786
 * builds an ASN object containing an float.
3787
 *
3788
 * @see asn_build_float
3789
 * 
3790
 * @param pkt     IN/OUT address of the begining of the buffer.
3791
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3792
 * @param offset  IN/OUT offset to the start of the buffer where to write
3793
 * @param r       IN if not zero reallocate the buffer to fit the 
3794
 *                needed size.
3795
 * @param type       IN - type of object
3796
 * @param floatp     IN - pointer to the float
3797
 * @param floatsize  IN - size of input buffer
3798
 *
3799
 * @return 1 on success, 0 on error
3800
 */
3801
3802
int
3803
asn_realloc_rbuild_float(u_char ** pkt, size_t * pkt_len,
3804
                         size_t * offset, int r,
3805
                         u_char type, const float *floatp, size_t floatsize)
3806
0
{
3807
0
    size_t          start_offset = *offset;
3808
0
    union {
3809
0
        float           floatVal;
3810
0
        int             intVal;
3811
0
        u_char          c[sizeof(float)];
3812
0
    } fu;
3813
3814
    /*
3815
     * Floatsize better not be larger than realistic.  
3816
     */
3817
0
    if (floatsize != sizeof(float) || floatsize > 122) {
3818
0
        return 0;
3819
0
    }
3820
3821
0
    while ((*pkt_len - *offset) < floatsize + 3) {
3822
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3823
0
            return 0;
3824
0
        }
3825
0
    }
3826
3827
    /*
3828
     * Correct for endian differences and copy value.  
3829
     */
3830
0
    fu.floatVal = *floatp;
3831
0
    fu.intVal = htonl(fu.intVal);
3832
0
    *offset += floatsize;
3833
0
    memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), floatsize);
3834
3835
    /*
3836
     * Put the special tag and length (3 bytes).  
3837
     */
3838
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) floatsize;
3839
0
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_FLOAT;
3840
0
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3841
3842
    /*
3843
     * Put the tag and length for the Opaque wrapper.  
3844
     */
3845
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3846
0
                                  ASN_OPAQUE, floatsize + 3)) {
3847
0
        if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
3848
0
                                            floatsize + 3)) {
3849
0
            return 0;
3850
0
        } else {
3851
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3852
0
                           *offset - start_offset);
3853
0
            DEBUGMSG(("dumpv_send", "Opaque Float:\t%f\n", *floatp));
3854
0
            return 1;
3855
0
        }
3856
0
    }
3857
3858
0
    return 0;
3859
0
}
3860
3861
/**
3862
 * @internal
3863
 * builds an ASN object containing an double.
3864
 *
3865
 * @see asn_build_double
3866
 * 
3867
 * @param pkt     IN/OUT address of the begining of the buffer.
3868
 * @param pkt_len IN/OUT address to an integer containing the size of pkt.
3869
 * @param offset  IN/OUT offset to the start of the buffer where to write
3870
 * @param r       IN if not zero reallocate the buffer to fit the 
3871
 *                needed size.
3872
 * @param type    IN - type of object
3873
 * @param doublep           IN - pointer to double
3874
 * @param doublesize  IN - size of input buffer
3875
 *
3876
 * @return 1 on success, 0 on error
3877
 */
3878
3879
int
3880
asn_realloc_rbuild_double(u_char ** pkt, size_t * pkt_len,
3881
                          size_t * offset, int r,
3882
                          u_char type, const double *doublep, size_t doublesize)
3883
0
{
3884
0
    size_t          start_offset = *offset;
3885
0
    long            tmp;
3886
0
    union {
3887
0
        double          doubleVal;
3888
0
        int             intVal[2];
3889
0
        u_char          c[sizeof(double)];
3890
0
    } fu;
3891
3892
    /*
3893
     * Doublesize better not be larger than realistic.  
3894
     */
3895
0
    if (doublesize != sizeof(double) || doublesize > 122) {
3896
0
        return 0;
3897
0
    }
3898
3899
0
    while ((*pkt_len - *offset) < doublesize + 3) {
3900
0
        if (!(r && asn_realloc(pkt, pkt_len))) {
3901
0
            return 0;
3902
0
        }
3903
0
    }
3904
3905
    /*
3906
     * Correct for endian differences and copy value.  
3907
     */
3908
0
    fu.doubleVal = *doublep;
3909
0
    tmp = htonl(fu.intVal[0]);
3910
0
    fu.intVal[0] = htonl(fu.intVal[1]);
3911
0
    fu.intVal[1] = tmp;
3912
0
    *offset += doublesize;
3913
0
    memcpy(*pkt + *pkt_len - *offset, &(fu.c[0]), doublesize);
3914
3915
    /*
3916
     * Put the special tag and length (3 bytes).  
3917
     */
3918
0
    *(*pkt + *pkt_len - (++*offset)) = (u_char) doublesize;
3919
0
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_DOUBLE;
3920
0
    *(*pkt + *pkt_len - (++*offset)) = ASN_OPAQUE_TAG1;
3921
3922
    /*
3923
     * Put the tag and length for the Opaque wrapper.  
3924
     */
3925
0
    if (asn_realloc_rbuild_header(pkt, pkt_len, offset, r,
3926
0
                                  ASN_OPAQUE, doublesize + 3)) {
3927
0
        if (_asn_realloc_build_header_check("build float", pkt, pkt_len,
3928
0
                                            doublesize + 3)) {
3929
0
            return 0;
3930
0
        } else {
3931
0
            DEBUGDUMPSETUP("send", (*pkt + *pkt_len - *offset),
3932
0
                           *offset - start_offset);
3933
0
            DEBUGMSG(("dumpv_send", "  Opaque Double:\t%f\n", *doublep));
3934
0
            return 1;
3935
0
        }
3936
0
    }
3937
3938
0
    return 0;
3939
0
}
3940
3941
#endif                          /* NETSNMP_WITH_OPAQUE_SPECIAL_TYPES */
3942
#endif                          /*  NETSNMP_USE_REVERSE_ASNENCODING  */
3943
/**
3944
 * @}
3945
 */