OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [rtos/] [ecos-2.0/] [packages/] [net/] [snmp/] [lib/] [v2_0/] [src/] [asn1.c] - Blame information for rev 593

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 27 unneback
//==========================================================================
2
//
3
//      ./lib/current/src/asn1.c
4
//
5
//
6
//==========================================================================
7
//####ECOSGPLCOPYRIGHTBEGIN####
8
// -------------------------------------------
9
// This file is part of eCos, the Embedded Configurable Operating System.
10
// Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
11
//
12
// eCos is free software; you can redistribute it and/or modify it under
13
// the terms of the GNU General Public License as published by the Free
14
// Software Foundation; either version 2 or (at your option) any later version.
15
//
16
// eCos is distributed in the hope that it will be useful, but WITHOUT ANY
17
// WARRANTY; without even the implied warranty of MERCHANTABILITY or
18
// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
19
// for more details.
20
//
21
// You should have received a copy of the GNU General Public License along
22
// with eCos; if not, write to the Free Software Foundation, Inc.,
23
// 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA.
24
//
25
// As a special exception, if other files instantiate templates or use macros
26
// or inline functions from this file, or you compile this file and link it
27
// with other works to produce a work based on this file, this file does not
28
// by itself cause the resulting work to be covered by the GNU General Public
29
// License. However the source code for this file must still be made available
30
// in accordance with section (3) of the GNU General Public License.
31
//
32
// This exception does not invalidate any other reasons why a work based on
33
// this file might be covered by the GNU General Public License.
34
//
35
// Alternative licenses for eCos may be arranged by contacting Red Hat, Inc.
36
// at http://sources.redhat.com/ecos/ecos-license/
37
// -------------------------------------------
38
//####ECOSGPLCOPYRIGHTEND####
39
//####UCDSNMPCOPYRIGHTBEGIN####
40
//
41
// -------------------------------------------
42
//
43
// Portions of this software may have been derived from the UCD-SNMP
44
// project,  <http://ucd-snmp.ucdavis.edu/>  from the University of
45
// California at Davis, which was originally based on the Carnegie Mellon
46
// University SNMP implementation.  Portions of this software are therefore
47
// covered by the appropriate copyright disclaimers included herein.
48
//
49
// The release used was version 4.1.2 of May 2000.  "ucd-snmp-4.1.2"
50
// -------------------------------------------
51
//
52
//####UCDSNMPCOPYRIGHTEND####
53
//==========================================================================
54
//#####DESCRIPTIONBEGIN####
55
//
56
// Author(s):    hmt
57
// Contributors: hmt
58
// Date:         2000-05-30
59
// Purpose:      Port of UCD-SNMP distribution to eCos.
60
// Description:  
61
//              
62
//
63
//####DESCRIPTIONEND####
64
//
65
//==========================================================================
66
/********************************************************************
67
       Copyright 1989, 1991, 1992 by Carnegie Mellon University
68
 
69
                          Derivative Work -
70
Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
71
 
72
                         All Rights Reserved
73
 
74
Permission to use, copy, modify and distribute this software and its
75
documentation for any purpose and without fee is hereby granted,
76
provided that the above copyright notice appears in all copies and
77
that both that copyright notice and this permission notice appear in
78
supporting documentation, and that the name of CMU and The Regents of
79
the University of California not be used in advertising or publicity
80
pertaining to distribution of the software without specific written
81
permission.
82
 
83
CMU AND THE REGENTS OF THE UNIVERSITY OF CALIFORNIA DISCLAIM ALL
84
WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
85
WARRANTIES OF MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL CMU OR
86
THE REGENTS OF THE UNIVERSITY OF CALIFORNIA BE LIABLE FOR ANY SPECIAL,
87
INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
88
FROM THE LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
89
CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
90
CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
91
*********************************************************************/
92
/*
93
 * Abstract Syntax Notation One, ASN.1
94
 * As defined in ISO/IS 8824 and ISO/IS 8825
95
 * This implements a subset of the above International Standards that
96
 * is sufficient to implement SNMP.
97
 *
98
 * Encodes abstract data types into a machine independent stream of bytes.
99
 *
100
 */
101
/**********************************************************************
102
        Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
103
 
104
                      All Rights Reserved
105
 
106
Permission to use, copy, modify, and distribute this software and its
107
documentation for any purpose and without fee is hereby granted,
108
provided that the above copyright notice appear in all copies and that
109
both that copyright notice and this permission notice appear in
110
supporting documentation, and that the name of CMU not be
111
used in advertising or publicity pertaining to distribution of the
112
software without specific, written prior permission.
113
 
114
CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
115
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
116
CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
117
ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
118
WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
119
ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
120
SOFTWARE.
121
******************************************************************/
122
#include <config.h>
123
 
124
#ifdef KINETICS
125
#include "gw.h"
126
#endif
127
 
128
#if HAVE_STRING_H
129
#include <string.h>
130
#else
131
#include <strings.h>
132
#endif
133
 
134
#include <sys/types.h>
135
#include <stdio.h>
136
#ifdef HAVE_STDLIB_H
137
#include <stdlib.h>
138
#endif
139
#if HAVE_WINSOCK_H
140
#include <winsock.h>
141
#endif
142
#if HAVE_NETINET_IN_H
143
#include <netinet/in.h>
144
#endif
145
 
146
#ifdef vms
147
#include <in.h>
148
#endif
149
 
150
#if HAVE_DMALLOC_H
151
#include <dmalloc.h>
152
#endif
153
 
154
#include "asn1.h"
155
#include "int64.h"
156
#include "snmp_debug.h"
157
#include "mib.h"
158
 
159
#ifndef NULL
160
#define NULL    0
161
#endif
162
 
163
#include "snmp_api.h"
164
#include "snmp_impl.h" /* to define ERROR_MSG */
165
 
166
static
167
void _asn_size_err(const char *str, size_t wrongsize, size_t rightsize)
168
{
169
    char ebuf[128];
170
 
171
    sprintf(ebuf,"%s size %d: s/b %d",str, wrongsize, rightsize);
172
    ERROR_MSG(ebuf);
173
}
174
 
175
static
176
void _asn_length_err(const char *str, size_t wrongsize, size_t rightsize)
177
{
178
    char ebuf[128];
179
 
180
    sprintf(ebuf,"%s length %d too large: exceeds %d",str, wrongsize, rightsize);
181
    ERROR_MSG(ebuf);
182
}
183
 
184
/*
185
 * call after asn_parse_length to verify result.
186
 */
187
static
188
int _asn_parse_length_check(const char *str,
189
                   u_char *bufp, u_char *data,
190
                   u_long plen, size_t dlen)
191
{
192
    char ebuf[128];
193
    size_t header_len;
194
 
195
    if (bufp == NULL){
196
        /* error message is set */
197
        return 1;
198
    }
199
    header_len = bufp - data;
200
    if (((size_t)plen + header_len) > dlen){
201
        sprintf(ebuf, "%s: message overflow: %d len + %d delta > %d len",
202
                str, (int)plen, (int)header_len, (int)dlen);
203
        ERROR_MSG(ebuf);
204
        return 1;
205
    }
206
    return 0;
207
}
208
 
209
/*
210
 * call after asn_build_header to verify result.
211
 */
212
static
213
int _asn_build_header_check(const char *str, u_char *data,
214
                      size_t datalen, size_t typedlen)
215
{
216
    char ebuf[128];
217
 
218
    if (data == NULL){
219
        /* error message is set */
220
        return 1;
221
    }
222
    if (datalen < typedlen){
223
        sprintf(ebuf, "%s: bad header, length too short: %d < %d", str, datalen, typedlen);
224
        ERROR_MSG(ebuf);
225
        return 1;
226
    }
227
    return 0;
228
}
229
 
230
/* checks the incoming packet for validity and returns its size or 0 */
231
int
232
asn_check_packet (u_char *pkt, size_t len)
233
{
234
  u_long asn_length;
235
 
236
  if (len < 2)
237
    return 0;      /* always too short */
238
 
239
  if (*pkt != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR))
240
    return -1;     /* wrong type */
241
 
242
  if (*(pkt+1) & 0x80) {
243
    /* long length */
244
    if ((int)len < (int)(*(pkt+1) & ~0x80)+2)
245
      return 0;    /* still to short, incomplete length */
246
    asn_parse_length(pkt+1, &asn_length);
247
    return (asn_length + 2 + (*(pkt+1) & ~0x80));
248
  } else {
249
    /* short length */
250
    return (*(pkt+1) + 2);
251
  }
252
}
253
 
254
static
255
int _asn_bitstring_check(const char * str, u_long asn_length, u_char datum)
256
{
257
    char ebuf[128];
258
 
259
    if (asn_length < 1){
260
        sprintf(ebuf,"%s: length %d too small", str, (int)asn_length);
261
        ERROR_MSG(ebuf);
262
        return 1;
263
    }
264
    if (datum > 7){
265
        sprintf(ebuf,"%s: datum %d >7: too large", str, (int)(datum));
266
        ERROR_MSG(ebuf);
267
        return 1;
268
    }
269
    return 0;
270
}
271
 
272
/*
273
 * asn_parse_int - pulls a long out of an ASN int type.
274
 *  On entry, datalength is input as the number of valid bytes following
275
 *   "data".  On exit, it is returned as the number of valid bytes
276
 *   following the end of this object.
277
 *
278
 *  Returns a pointer to the first byte past the end
279
 *   of this object (i.e. the start of the next object).
280
 *  Returns NULL on any error.
281
 
282
  u_char * asn_parse_int(
283
      u_char     *data         IN - pointer to start of object
284
      int        *datalength   IN/OUT - number of valid bytes left in buffer
285
      u_char     *type         OUT - asn type of object
286
      long       *intp         IN/OUT - pointer to start of output buffer
287
      int         intsize      IN - size of output buffer
288
*/
289
 
290
u_char *
291
asn_parse_int(u_char *data,
292
              size_t *datalength,
293
              u_char *type,
294
              long *intp,
295
              size_t intsize)
296
{
297
/*
298
 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
299
 */
300
    static const char *errpre = "parse int";
301
    register u_char *bufp = data;
302
    u_long          asn_length;
303
    register long   value = 0;
304
 
305
    if (intsize != sizeof (long)){
306
        _asn_size_err(errpre, intsize, sizeof(long));
307
        return NULL;
308
    }
309
    *type = *bufp++;
310
    bufp = asn_parse_length(bufp, &asn_length);
311
    if (_asn_parse_length_check(errpre, bufp, data, asn_length, *datalength))
312
        return NULL;
313
 
314
    if ((size_t)asn_length > intsize){
315
        _asn_length_err(errpre, (size_t)asn_length, intsize);
316
        return NULL;
317
    }
318
 
319
    *datalength -= (int)asn_length + (bufp - data);
320
    if (*bufp & 0x80)
321
        value = -1; /* integer is negative */
322
 
323
    DEBUGDUMPSETUP("dump_recv", data, bufp - data + asn_length);
324
 
325
    while(asn_length--)
326
        value = (value << 8) | *bufp++;
327
 
328
    DEBUGMSG(("dump_recv", "  ASN Integer:\t%ld (0x%.2X)\n", value, value));
329
 
330
    *intp = value;
331
    return bufp;
332
}
333
 
334
 
335
/*
336
 * asn_parse_unsigned_int - pulls an unsigned long out of an ASN int type.
337
 *  On entry, datalength is input as the number of valid bytes following
338
 *   "data".  On exit, it is returned as the number of valid bytes
339
 *   following the end of this object.
340
 *
341
 *  Returns a pointer to the first byte past the end
342
 *   of this object (i.e. the start of the next object).
343
 *  Returns NULL on any error.
344
 
345
  u_char * asn_parse_unsigned_int(
346
      u_char     *data         IN - pointer to start of object
347
      int        *datalength   IN/OUT - number of valid bytes left in buffer
348
      u_char     *type         OUT - asn type of object
349
      u_long     *intp         IN/OUT - pointer to start of output buffer
350
      int         intsize      IN - size of output buffer
351
 */
352
u_char *
353
asn_parse_unsigned_int(u_char *data,
354
                       size_t *datalength,
355
                       u_char *type,
356
                       u_long *intp,
357
                       size_t intsize)
358
{
359
/*
360
 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
361
 */
362
    static const char *errpre = "parse uint";
363
    register u_char *bufp = data;
364
    u_long          asn_length;
365
    register u_long value = 0;
366
 
367
    if (intsize != sizeof (long)){
368
        _asn_size_err(errpre, intsize, sizeof(long));
369
        return NULL;
370
    }
371
    *type = *bufp++;
372
    bufp = asn_parse_length(bufp, &asn_length);
373
    if (_asn_parse_length_check(errpre, bufp, data, asn_length, *datalength))
374
        return NULL;
375
 
376
    if (((int)asn_length > (intsize + 1)) ||
377
        (((int)asn_length == intsize + 1) && *bufp != 0x00)){
378
        _asn_length_err(errpre, (size_t)asn_length, intsize);
379
        return NULL;
380
    }
381
    *datalength -= (int)asn_length + (bufp - data);
382
    if (*bufp & 0x80)
383
        value = ~value; /* integer is negative */
384
 
385
    DEBUGDUMPSETUP("dump_recv", data, bufp - data + asn_length);
386
 
387
    while(asn_length--)
388
        value = (value << 8) | *bufp++;
389
 
390
    DEBUGMSG(("dump_recv", "  ASN UInteger:\t%ld (0x%.2X)\n", value, value));
391
 
392
    *intp = value;
393
    return bufp;
394
}
395
 
396
 
397
/*
398
 * asn_build_int - builds an ASN object containing an integer.
399
 *  On entry, datalength is input as the number of valid bytes following
400
 *   "data".  On exit, it is returned as the number of valid bytes
401
 *   following the end of this object.
402
 *
403
 *  Returns a pointer to the first byte past the end
404
 *   of this object (i.e. the start of the next object).
405
 *  Returns NULL on any error.
406
 
407
  u_char * asn_build_int(
408
      u_char     *data         IN - pointer to start of output buffer
409
      int        *datalength   IN/OUT - number of valid bytes left in buffer
410
      int         type         IN  - asn type of object
411
      long       *intp         IN - pointer to start of long integer
412
      int         intsize      IN - size of input buffer
413
 */
414
u_char *
415
asn_build_int(u_char *data,
416
              size_t *datalength,
417
              u_char type,
418
              long *intp,
419
              size_t intsize)
420
{
421
/*
422
 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
423
 */
424
        static const char *errpre = "build int";
425
    register long integer;
426
    register u_long mask;
427
 
428
    if (intsize != sizeof (long)){
429
        _asn_size_err(errpre, intsize, sizeof(long));
430
        return NULL;
431
    }
432
    integer = *intp;
433
    /*
434
     * Truncate "unnecessary" bytes off of the most significant end of this
435
     * 2's complement integer.  There should be no sequence of 9
436
     * consecutive 1's or 0's at the most significant end of the
437
     * integer.
438
     */
439
    mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
440
    /* mask is 0xFF800000 on a big-endian machine */
441
    while((((integer & mask) == 0) || ((integer & mask) == mask))
442
          && intsize > 1){
443
        intsize--;
444
        integer <<= 8;
445
    }
446
    data = asn_build_header(data, datalength, type, intsize);
447
    if (_asn_build_header_check(errpre,data,*datalength,intsize))
448
        return NULL;
449
 
450
    *datalength -= intsize;
451
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
452
    /* mask is 0xFF000000 on a big-endian machine */
453
    while(intsize--){
454
        *data++ = (u_char)((integer & mask) >> (8 * (sizeof(long) - 1)));
455
        integer <<= 8;
456
    }
457
    return data;
458
}
459
 
460
 
461
/*
462
 * asn_build_unsigned_int - builds an ASN object containing an integer.
463
 *  On entry, datalength is input as the number of valid bytes following
464
 *   "data".  On exit, it is returned as the number of valid bytes
465
 *   following the end of this object.
466
 *
467
 *  Returns a pointer to the first byte past the end
468
 *   of this object (i.e. the start of the next object).
469
 *  Returns NULL on any error.
470
 
471
  u_char * asn_build_unsigned_int(
472
      u_char     *data         IN - pointer to start of output buffer
473
      int        *datalength   IN/OUT - number of valid bytes left in buffer
474
      u_char      type         IN  - asn type of object
475
      u_long     *intp         IN - pointer to start of long integer
476
      int         intsize      IN - size of input buffer
477
 */
478
u_char *
479
asn_build_unsigned_int(u_char *data,
480
                       size_t *datalength,
481
                       u_char type,
482
                       u_long *intp,
483
                       size_t intsize)
484
{
485
/*
486
 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
487
 */
488
        static const char *errpre = "build uint";
489
    register u_long integer;
490
    register u_long mask;
491
    int add_null_byte = 0;
492
 
493
    if (intsize != sizeof (long)){
494
        _asn_size_err(errpre, intsize, sizeof(long));
495
        return NULL;
496
    }
497
    integer = *intp;
498
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
499
    /* mask is 0xFF000000 on a big-endian machine */
500
    if ((u_char)((integer & mask) >> (8 * (sizeof(long) - 1))) & 0x80){
501
        /* if MSB is set */
502
        add_null_byte = 1;
503
        intsize++;
504
    } else {
505
        /*
506
         * Truncate "unnecessary" bytes off of the most significant end of this 2's complement integer.
507
         * There should be no sequence of 9 consecutive 1's or 0's at the most significant end of the
508
         * integer.
509
         */
510
        mask = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
511
        /* mask is 0xFF800000 on a big-endian machine */
512
        while((((integer & mask) == 0) || ((integer & mask) == mask)) && intsize > 1){
513
            intsize--;
514
            integer <<= 8;
515
        }
516
    }
517
    data = asn_build_header(data, datalength, type, intsize);
518
    if (_asn_build_header_check(errpre,data,*datalength,intsize))
519
        return NULL;
520
 
521
    *datalength -= intsize;
522
    if (add_null_byte == 1){
523
        *data++ = '\0';
524
        intsize--;
525
    }
526
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
527
    /* mask is 0xFF000000 on a big-endian machine */
528
    while(intsize--){
529
        *data++ = (u_char)((integer & mask) >> (8 * (sizeof(long) - 1)));
530
        integer <<= 8;
531
    }
532
    return data;
533
}
534
 
535
 
536
/*
537
 * asn_parse_string - pulls an octet string out of an ASN octet string type.
538
 *  On entry, datalength is input as the number of valid bytes following
539
 *   "data".  On exit, it is returned as the number of valid bytes
540
 *   following the beginning of the next object.
541
 *
542
 *  "string" is filled with the octet string.
543
 *
544
 *  Returns a pointer to the first byte past the end
545
 *   of this object (i.e. the start of the next object).
546
 *  Returns NULL on any error.
547
 *
548
 * u_char * asn_parse_string(
549
 *     u_char     *data         IN - pointer to start of object
550
 *     int        *datalength   IN/OUT - number of valid bytes left in buffer
551
 *     u_char     *type         OUT - asn type of object
552
 *     u_char     *string       IN/OUT - pointer to start of output buffer
553
 *     int        *strlength    IN/OUT - size of output buffer
554
 *
555
 *
556
 * ASN.1 octet string   ::=      primstring | cmpdstring
557
 * primstring           ::= 0x04 asnlength byte {byte}*
558
 * cmpdstring           ::= 0x24 asnlength string {string}*
559
 */
560
u_char *
561
asn_parse_string(u_char *data,
562
                 size_t *datalength,
563
                 u_char *type,
564
                 u_char *string,
565
                 size_t *strlength)
566
{
567
    static const char *errpre = "parse string";
568
    u_char *bufp = data;
569
    u_long  asn_length;
570
 
571
    *type = *bufp++;
572
    bufp = asn_parse_length(bufp, &asn_length);
573
    if (_asn_parse_length_check(errpre, bufp, data, asn_length, *datalength))
574
        return NULL;
575
 
576
    if ((int)asn_length > *strlength){
577
        _asn_length_err(errpre, (size_t)asn_length, *strlength);
578
        return NULL;
579
    }
580
 
581
    DEBUGDUMPSETUP("dump_recv", data, bufp - data + asn_length);
582
 
583
    memmove(string, bufp, asn_length);
584
    if (*strlength > (int)asn_length)
585
      string[asn_length] = 0;
586
    *strlength = (int)asn_length;
587
    *datalength -= (int)asn_length + (bufp - data);
588
 
589
    DEBUGIF("dump_recv") {
590
      char *buf = (char *)malloc(1+asn_length);
591
      sprint_asciistring(buf, string, asn_length);
592
      DEBUGMSG(("dump_recv", "  ASN String:\t%s\n", buf));
593
      free (buf);
594
    }
595
 
596
    return bufp + asn_length;
597
}
598
 
599
 
600
/*
601
 * asn_build_string - Builds an ASN octet string object containing the input string.
602
 *  On entry, datalength is input as the number of valid bytes following
603
 *   "data".  On exit, it is returned as the number of valid bytes
604
 *   following the beginning of the next object.
605
 *
606
 *  Returns a pointer to the first byte past the end
607
 *   of this object (i.e. the start of the next object).
608
 *  Returns NULL on any error.
609
 
610
  u_char * asn_build_string(
611
      u_char     *data         IN - pointer to start of object
612
      int        *datalength   IN/OUT - number of valid bytes left in buffer
613
      u_char      type         IN - asn type of object
614
      u_char     *string       IN - pointer to start of input buffer
615
      int         strlength    IN - size of input buffer
616
 */
617
u_char *
618
asn_build_string(u_char *data,
619
                 size_t *datalength,
620
                 u_char type,
621
                 const u_char *string,
622
                 size_t strlength)
623
{
624
/*
625
 * ASN.1 octet string ::= primstring | cmpdstring
626
 * primstring ::= 0x04 asnlength byte {byte}*
627
 * cmpdstring ::= 0x24 asnlength string {string}*
628
 * This code will never send a compound string.
629
 */
630
    data = asn_build_header(data, datalength, type, strlength);
631
    if (_asn_build_header_check("build string", data, *datalength, strlength))
632
        return NULL;
633
 
634
    if (strlength) {
635
      if (string == NULL) {
636
        memset(data, 0, strlength);
637
      } else {
638
        memmove(data, string, strlength);
639
      }
640
    }
641
    *datalength -= strlength;
642
    return data + strlength;
643
}
644
 
645
 
646
 
647
/*
648
 * asn_parse_header - interprets the ID and length of the current object.
649
 *  On entry, datalength is input as the number of valid bytes following
650
 *   "data".  On exit, it is returned as the number of valid bytes
651
 *   in this object following the id and length.
652
 *
653
 *  Returns a pointer to the first byte of the contents of this object.
654
 *  Returns NULL on any error.
655
 
656
  u_char * asn_parse_header(
657
      u_char     *data         IN - pointer to start of object
658
      int        *datalength   IN/OUT - number of valid bytes left in buffer
659
      u_char     *type         OUT - asn type of object
660
 */
661
u_char *
662
asn_parse_header(u_char *data,
663
                 size_t *datalength,
664
                 u_char *type)
665
{
666
    register u_char *bufp;
667
    u_long          asn_length;
668
 
669
    if (!data || !datalength || !type) {
670
        ERROR_MSG("parse header: NULL pointer");
671
        return NULL;
672
    }
673
    bufp = data;
674
    /* this only works on data types < 30, i.e. no extension octets */
675
    if (IS_EXTENSION_ID(*bufp)){
676
        ERROR_MSG("can't process ID >= 30");
677
        return NULL;
678
    }
679
    *type = *bufp;
680
    bufp = asn_parse_length(bufp + 1, &asn_length);
681
    if (_asn_parse_length_check("parse header", bufp, data, asn_length, *datalength))
682
        return NULL;
683
 
684
    DEBUGDUMPSETUP("dump_recv", data, (bufp-data));
685
    DEBUGMSG(("dump_recv", "  ASN Header: 0x%.2X, len = %d (0x%X)\n", *data,
686
              asn_length, asn_length));
687
 
688
#ifdef OPAQUE_SPECIAL_TYPES
689
 
690
    if ((*type == ASN_OPAQUE) &&
691
        (*bufp == ASN_OPAQUE_TAG1)) {
692
      DEBUGINDENTMORE();
693
      DEBUGDUMPSETUP("dump_recv", data, 1);
694
      DEBUGMSG(("dump_recv", "Opaque:\t%.2x\n", *bufp));
695
      DEBUGINDENTLESS();
696
 
697
      /* check if 64-but counter */
698
      switch(*(bufp+1)) {
699
        case ASN_OPAQUE_COUNTER64:
700
        case ASN_OPAQUE_U64:
701
        case ASN_OPAQUE_FLOAT:
702
        case ASN_OPAQUE_DOUBLE:
703
        case ASN_OPAQUE_I64:
704
          *type = *(bufp+1);
705
          break;
706
 
707
        default:
708
          /* just an Opaque */
709
          *datalength = (int)asn_length;
710
          return bufp;
711
      }
712
      /* value is encoded as special format */
713
      bufp = asn_parse_length(bufp + 2, &asn_length);
714
      if (_asn_parse_length_check("parse opaque header", bufp, data,
715
                  asn_length, *datalength))
716
        return NULL;
717
    }
718
#endif /* OPAQUE_SPECIAL_TYPES */
719
 
720
    *datalength = (int)asn_length;
721
 
722
    return bufp;
723
}
724
 
725
/*
726
 * same as asn_parse_header with test for expected type.
727
 */
728
u_char *
729
asn_parse_sequence(u_char       *data,
730
                 size_t *datalength,
731
                 u_char *type,
732
                 u_char expected_type, /* must be this type */
733
                 const char *estr)      /* error message prefix */
734
{
735
    data = asn_parse_header(data, datalength, type);
736
    if (data && (*type != expected_type)) {
737
        char ebuf[128];
738
        sprintf(ebuf, "%s header type %02X: s/b %02X", estr,
739
                        (u_char)*type, (u_char)expected_type);
740
        ERROR_MSG(ebuf);
741
        return NULL;
742
    }
743
    return data;
744
}
745
 
746
 
747
 
748
/*
749
 * asn_build_header - builds an ASN header for an object with the ID and
750
 * length specified.
751
 *  On entry, datalength is input as the number of valid bytes following
752
 *   "data".  On exit, it is returned as the number of valid bytes
753
 *   in this object following the id and length.
754
 *
755
 *  This only works on data types < 30, i.e. no extension octets.
756
 *  The maximum length is 0xFFFF;
757
 *
758
 *  Returns a pointer to the first byte of the contents of this object.
759
 *  Returns NULL on any error.
760
 
761
  u_char * asn_build_header(
762
      u_char     *data         IN - pointer to start of object
763
      size_t     *datalength   IN/OUT - number of valid bytes left in buffer
764
      u_char      type         IN - asn type of object
765
      size_t      length       IN - length of object
766
 */
767
u_char *
768
asn_build_header (u_char *data,
769
                  size_t *datalength,
770
                  u_char type,
771
                  size_t length)
772
{
773
    char ebuf[128];
774
 
775
    if (*datalength < 1){
776
        sprintf(ebuf, "bad header length < 1 :%d, %d", *datalength, length);
777
        ERROR_MSG(ebuf);
778
        return NULL;
779
    }
780
    *data++ = type;
781
    (*datalength)--;
782
    return asn_build_length(data, datalength, length);
783
}
784
 
785
/*
786
 * asn_build_sequence - builds an ASN header for a sequence with the ID and
787
 * length specified.
788
 *  On entry, datalength is input as the number of valid bytes following
789
 *   "data".  On exit, it is returned as the number of valid bytes
790
 *   in this object following the id and length.
791
 *
792
 *  This only works on data types < 30, i.e. no extension octets.
793
 *  The maximum length is 0xFFFF;
794
 *
795
 *  Returns a pointer to the first byte of the contents of this object.
796
 *  Returns NULL on any error.
797
 
798
  u_char * asn_build_sequence(
799
      u_char     *data         IN - pointer to start of object
800
      int        *datalength   IN/OUT - number of valid bytes left in buffer
801
      u_char      type         IN - asn type of object
802
      int         length       IN - length of object
803
 */
804
u_char *
805
asn_build_sequence(u_char *data,
806
                  size_t *datalength,
807
                  u_char type,
808
                  size_t length)
809
{
810
    static const char *errpre = "build seq";
811
    char ebuf[128];
812
 
813
    if (*datalength < 4){
814
        sprintf(ebuf, "%s: length %d < 4: PUNT", errpre, (int)*datalength);
815
        ERROR_MSG(ebuf);
816
        return NULL;
817
    }
818
    *datalength -= 4;
819
    *data++ = type;
820
    *data++ = (u_char)(0x02 | ASN_LONG_LEN);
821
    *data++ = (u_char)((length >> 8) & 0xFF);
822
    *data++ = (u_char)(length & 0xFF);
823
    return data;
824
}
825
 
826
/*
827
 * asn_parse_length - interprets the length of the current object.
828
 *  On exit, length contains the value of this length field.
829
 *
830
 *  Returns a pointer to the first byte after this length
831
 *  field (aka: the start of the data field).
832
 *  Returns NULL on any error.
833
 
834
  u_char * asn_parse_length(
835
      u_char     *data         IN - pointer to start of length field
836
      u_long     *length       OUT - value of length field
837
 */
838
u_char *
839
asn_parse_length(u_char  *data,
840
                 u_long  *length)
841
{
842
    static const char *errpre = "parse length";
843
    char ebuf[128];
844
    register u_char lengthbyte;
845
 
846
    if (!data || !length) {
847
        ERROR_MSG("parse length: NULL pointer");
848
        return NULL;
849
    }
850
    lengthbyte = *data;
851
 
852
    if (lengthbyte & ASN_LONG_LEN){
853
        lengthbyte &= ~ASN_LONG_LEN;    /* turn MSb off */
854
        if (lengthbyte == 0){
855
            sprintf(ebuf, "%s: indefinite length not supported", errpre);
856
            ERROR_MSG(ebuf);
857
            return NULL;
858
        }
859
        if (lengthbyte > sizeof(long)){
860
            sprintf(ebuf, "%s: data length %d > %d not supported", errpre,
861
                 lengthbyte, sizeof(long));
862
            ERROR_MSG(ebuf);
863
            return NULL;
864
        }
865
        data++;
866
        *length = 0;  /* protect against short lengths */
867
        while(lengthbyte--) {
868
                *length <<= 8;
869
                *length |= *data++;
870
        }
871
        return data;
872
    } else { /* short asnlength */
873
        *length = (long)lengthbyte;
874
        return data + 1;
875
    }
876
}
877
 
878
/*
879
 
880
  u_char * asn_build_length(
881
      u_char     *data         IN - pointer to start of object
882
      int        *datalength   IN/OUT - number of valid bytes left in buffer
883
      int         length       IN - length of object
884
 */
885
u_char *
886
asn_build_length(u_char *data,
887
                 size_t *datalength,
888
                 size_t length)
889
{
890
    static const char *errpre = "build length";
891
    char ebuf[128];
892
 
893
    u_char    *start_data = data;
894
 
895
    /* no indefinite lengths sent */
896
    if (length < 0x80){
897
        if (*datalength < 1){
898
            sprintf(ebuf, "%s: bad length < 1 :%d, %d",errpre,*datalength,length);
899
            ERROR_MSG(ebuf);
900
            return NULL;
901
        }
902
        *data++ = (u_char)length;
903
    } else if (length <= 0xFF){
904
        if (*datalength < 2){
905
            sprintf(ebuf, "%s: bad length < 2 :%d, %d",errpre,*datalength,length);
906
            ERROR_MSG(ebuf);
907
            return NULL;
908
        }
909
        *data++ = (u_char)(0x01 | ASN_LONG_LEN);
910
        *data++ = (u_char)length;
911
    } else { /* 0xFF < length <= 0xFFFF */
912
        if (*datalength < 3){
913
            sprintf(ebuf, "%s: bad length < 3 :%d, %d",errpre,*datalength,length);
914
            ERROR_MSG(ebuf);
915
            return NULL;
916
        }
917
        *data++ = (u_char)(0x02 | ASN_LONG_LEN);
918
        *data++ = (u_char)((length >> 8) & 0xFF);
919
        *data++ = (u_char)(length & 0xFF);
920
    }
921
    *datalength -= (data - start_data);
922
    return data;
923
 
924
}
925
 
926
/*
927
 * asn_parse_objid - pulls an object indentifier out of an ASN object identifier type.
928
 *  On entry, datalength is input as the number of valid bytes following
929
 *   "data".  On exit, it is returned as the number of valid bytes
930
 *   following the beginning of the next object.
931
 *
932
 *  "objid" is filled with the object identifier.
933
 *
934
 *  Returns a pointer to the first byte past the end
935
 *   of this object (i.e. the start of the next object).
936
 *  Returns NULL on any error.
937
 
938
  u_char * asn_parse_objid(
939
      u_char     *data         IN - pointer to start of object
940
      int        *datalength   IN/OUT - number of valid bytes left in buffer
941
      u_char     *type         OUT - asn type of object
942
      oid        *objid        IN/OUT - pointer to start of output buffer
943
      int        *objidlength  IN/OUT - number of sub-id's in objid
944
 */
945
u_char *
946
asn_parse_objid(u_char *data,
947
                size_t *datalength,
948
                u_char *type,
949
                oid *objid,
950
                size_t *objidlength)
951
{
952
/*
953
 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
954
 * subidentifier ::= {leadingbyte}* lastbyte
955
 * leadingbyte ::= 1 7bitvalue
956
 * lastbyte ::= 0 7bitvalue
957
 */
958
    register u_char *bufp = data;
959
    register oid *oidp = objid + 1;
960
    register u_long subidentifier;
961
    register long   length;
962
    u_long          asn_length;
963
 
964
    *type = *bufp++;
965
    bufp = asn_parse_length(bufp, &asn_length);
966
    if (_asn_parse_length_check("parse objid", bufp, data,
967
                    asn_length, *datalength))
968
        return NULL;
969
 
970
    *datalength -= (int)asn_length + (bufp - data);
971
 
972
    DEBUGDUMPSETUP("dump_recv", data, bufp - data + asn_length);
973
 
974
    /* Handle invalid object identifier encodings of the form 06 00 robustly */
975
    if (asn_length == 0)
976
        objid[0] = objid[1] = 0;
977
 
978
    length = asn_length;
979
    (*objidlength)--;   /* account for expansion of first byte */
980
 
981
    while (length > 0 && (*objidlength)-- > 0){
982
        subidentifier = 0;
983
        do {    /* shift and add in low order 7 bits */
984
            subidentifier = (subidentifier << 7) + (*(u_char *)bufp & ~ASN_BIT8);
985
            length--;
986
        } while (*(u_char *)bufp++ & ASN_BIT8); /* last byte has high bit clear */
987
/*?? note, this test will never be true, since the largest value
988
     of subidentifier is the value of MAX_SUBID! */
989
        if (subidentifier > (u_long)MAX_SUBID){
990
            ERROR_MSG("subidentifier too large");
991
            return NULL;
992
        }
993
        *oidp++ = (oid)subidentifier;
994
    }
995
 
996
    /*
997
     * The first two subidentifiers are encoded into the first component
998
     * with the value (X * 40) + Y, where:
999
     *  X is the value of the first subidentifier.
1000
     *  Y is the value of the second subidentifier.
1001
     */
1002
    subidentifier = (u_long)objid[1];
1003
    if (subidentifier == 0x2B){
1004
        objid[0] = 1;
1005
        objid[1] = 3;
1006
    } else {
1007
        if (subidentifier < 40) {
1008
            objid[0] = 0;
1009
            objid[1] = subidentifier;
1010
        } else if (subidentifier < 80) {
1011
            objid[0] = 1;
1012
            objid[1] = subidentifier - 40;
1013
        } else if (subidentifier < 120) {
1014
            objid[0] = 2;
1015
            objid[1] = subidentifier - 80;
1016
        } else {
1017
            objid[1] = (subidentifier % 40);
1018
            objid[0] = ((subidentifier - objid[1]) / 40);
1019
        }
1020
    }
1021
 
1022
    *objidlength = (int)(oidp - objid);
1023
 
1024
    DEBUGMSG(("dump_recv", "  ASN ObjID: "));
1025
    DEBUGMSGOID(("dump_recv", objid, *objidlength));
1026
    DEBUGMSG(("dump_recv", "\n"));
1027
    return bufp;
1028
}
1029
 
1030
/*
1031
 * asn_build_objid - Builds an ASN object identifier object containing the
1032
 * input string.
1033
 *  On entry, datalength is input as the number of valid bytes following
1034
 *   "data".  On exit, it is returned as the number of valid bytes
1035
 *   following the beginning of the next object.
1036
 *
1037
 *  Returns a pointer to the first byte past the end
1038
 *   of this object (i.e. the start of the next object).
1039
 *  Returns NULL on any error.
1040
 
1041
  u_char * asn_build_objid(
1042
      u_char     *data         IN - pointer to start of object
1043
      int        *datalength   IN/OUT - number of valid bytes left in buffer
1044
      int        type         IN - asn type of object
1045
      oid        *objid        IN - pointer to start of input buffer
1046
      int         objidlength  IN - number of sub-id's in objid
1047
 */
1048
u_char *
1049
asn_build_objid(u_char *data,
1050
                size_t *datalength,
1051
                u_char type,
1052
                oid *objid,
1053
                size_t objidlength)
1054
{
1055
/*
1056
 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
1057
 * subidentifier ::= {leadingbyte}* lastbyte
1058
 * leadingbyte ::= 1 7bitvalue
1059
 * lastbyte ::= 0 7bitvalue
1060
 */
1061
    size_t asnlength;
1062
    register oid *op = objid;
1063
    u_char objid_size[MAX_OID_LEN];
1064
    register u_long objid_val;
1065
    u_long first_objid_val;
1066
    register int i;
1067
 
1068
    /* check if there are at least 2 sub-identifiers */
1069
    if (objidlength == 0){
1070
        /* there are not, so make OID have two with value of zero */
1071
        objid_val = 0;
1072
        objidlength = 2;
1073
    } else if (objidlength == 1){
1074
        /* encode the first value */
1075
        objid_val = (op[0] * 40);
1076
        objidlength = 2;
1077
        op++;
1078
    } else {
1079
        /* combine the first two values */
1080
        if ( op[1] > 40 ) {
1081
            ERROR_MSG("build objid: bad second subidentifier");
1082
            return NULL;
1083
        }
1084
        objid_val = (op[0] * 40) + op[1];
1085
        op += 2;
1086
    }
1087
    first_objid_val = objid_val;
1088
 
1089
    /* calculate the number of bytes needed to store the encoded value */
1090
    for (i = 1, asnlength = 0;;) {
1091
        if (objid_val < (unsigned)0x80) {
1092
            objid_size[i] = 1;
1093
            asnlength += 1;
1094
        } else if (objid_val < (unsigned)0x4000) {
1095
            objid_size[i] = 2;
1096
            asnlength += 2;
1097
        } else if (objid_val < (unsigned)0x200000) {
1098
            objid_size[i] = 3;
1099
            asnlength += 3;
1100
        } else if (objid_val < (unsigned)0x10000000) {
1101
            objid_size[i] = 4;
1102
            asnlength += 4;
1103
        } else {
1104
            objid_size[i] = 5;
1105
            asnlength += 5;
1106
        }
1107
        i++;
1108
        if (i >= (int)objidlength)
1109
            break;
1110
        objid_val = *op++;
1111
    }
1112
 
1113
    /* store the ASN.1 tag and length */
1114
    data = asn_build_header(data, datalength, type, asnlength);
1115
    if (_asn_build_header_check("build objid", data, *datalength, asnlength))
1116
        return NULL;
1117
 
1118
    /* store the encoded OID value */
1119
    for (i = 1, objid_val = first_objid_val, op = objid+2;
1120
                                i < (int)objidlength;
1121
                i++) {
1122
      if (i != 1) objid_val = *op++;
1123
        switch (objid_size[i]) {
1124
        case 1:
1125
            *data++ = (u_char)objid_val;
1126
            break;
1127
 
1128
        case 2:
1129
            *data++ = (u_char)((objid_val>>7) | 0x80);
1130
            *data++ = (u_char)(objid_val & 0x07f);
1131
            break;
1132
 
1133
        case 3:
1134
            *data++ = (u_char)((objid_val>>14) | 0x80);
1135
            *data++ = (u_char)((objid_val>>7 & 0x7f) | 0x80);
1136
            *data++ = (u_char)(objid_val & 0x07f);
1137
            break;
1138
 
1139
        case 4:
1140
            *data++ = (u_char)((objid_val>>21) | 0x80);
1141
            *data++ = (u_char)((objid_val>>14 & 0x7f) | 0x80);
1142
            *data++ = (u_char)((objid_val>>7 & 0x7f) | 0x80);
1143
            *data++ = (u_char)(objid_val & 0x07f);
1144
            break;
1145
 
1146
        case 5:
1147
            *data++ = (u_char)((objid_val>>28) | 0x80);
1148
            *data++ = (u_char)((objid_val>>21 & 0x7f) | 0x80);
1149
            *data++ = (u_char)((objid_val>>14 & 0x7f) | 0x80);
1150
            *data++ = (u_char)((objid_val>>7 & 0x7f) | 0x80);
1151
            *data++ = (u_char)(objid_val & 0x07f);
1152
            break;
1153
        }
1154
    }
1155
 
1156
    /* return the length and data ptr */
1157
    *datalength -= asnlength;
1158
    return data;
1159
}
1160
 
1161
/*
1162
 * asn_parse_null - Interprets an ASN null type.
1163
 *  On entry, datalength is input as the number of valid bytes following
1164
 *   "data".  On exit, it is returned as the number of valid bytes
1165
 *   following the beginning of the next object.
1166
 *
1167
 *  Returns a pointer to the first byte past the end
1168
 *   of this object (i.e. the start of the next object).
1169
 *  Returns NULL on any error.
1170
 
1171
  u_char * asn_parse_null(
1172
      u_char     *data         IN - pointer to start of object
1173
      int        *datalength   IN/OUT - number of valid bytes left in buffer
1174
      u_char     *type         OUT - asn type of object
1175
 */
1176
u_char *
1177
asn_parse_null(u_char *data,
1178
               size_t *datalength,
1179
               u_char *type)
1180
{
1181
/*
1182
 * ASN.1 null ::= 0x05 0x00
1183
 */
1184
    register u_char   *bufp = data;
1185
    u_long          asn_length;
1186
 
1187
    *type = *bufp++;
1188
    bufp = asn_parse_length(bufp, &asn_length);
1189
    if (bufp == NULL){
1190
        ERROR_MSG("parse null: bad length");
1191
        return NULL;
1192
    }
1193
    if (asn_length != 0){
1194
        ERROR_MSG("parse null: malformed ASN.1 null");
1195
        return NULL;
1196
    }
1197
 
1198
    *datalength -= (bufp - data);
1199
 
1200
    DEBUGDUMPSETUP("dump_recv", data, bufp - data);
1201
    DEBUGMSG(("dump_recv", "  ASN NULL\n"));
1202
 
1203
    return bufp + asn_length;
1204
}
1205
 
1206
 
1207
/*
1208
 * asn_build_null - Builds an ASN null object.
1209
 *  On entry, datalength is input as the number of valid bytes following
1210
 *   "data".  On exit, it is returned as the number of valid bytes
1211
 *   following the beginning of the next object.
1212
 *
1213
 *  Returns a pointer to the first byte past the end
1214
 *   of this object (i.e. the start of the next object).
1215
 *  Returns NULL on any error.
1216
 
1217
  u_char * asn_build_null(
1218
      u_char     *data         IN - pointer to start of object
1219
      int        *datalength   IN/OUT - number of valid bytes left in buffer
1220
      u_char      type         IN - asn type of object
1221
 */
1222
u_char *
1223
asn_build_null(u_char *data,
1224
               size_t *datalength,
1225
               u_char type)
1226
{
1227
/*
1228
 * ASN.1 null ::= 0x05 0x00
1229
 */
1230
    return asn_build_header(data, datalength, type, 0);
1231
}
1232
 
1233
/*
1234
 * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
1235
 *  On entry, datalength is input as the number of valid bytes following
1236
 *   "data".  On exit, it is returned as the number of valid bytes
1237
 *   following the beginning of the next object.
1238
 *
1239
 *  "string" is filled with the bit string.
1240
 *
1241
 *  Returns a pointer to the first byte past the end
1242
 *   of this object (i.e. the start of the next object).
1243
 *  Returns NULL on any error.
1244
 
1245
  u_char * asn_parse_bitstring(
1246
      u_char     *data         IN - pointer to start of object
1247
      size_t     *datalength   IN/OUT - number of valid bytes left in buffer
1248
      u_char     *type         OUT - asn type of object
1249
      u_char     *string       IN/OUT - pointer to start of output buffer
1250
      size_t     *strlength    IN/OUT - size of output buffer
1251
 */
1252
u_char *
1253
asn_parse_bitstring(u_char *data,
1254
                    size_t *datalength,
1255
                    u_char *type,
1256
                    u_char *string,
1257
                    size_t *strlength)
1258
{
1259
/*
1260
 * bitstring ::= 0x03 asnlength unused {byte}*
1261
 */
1262
    static const char *errpre = "parse bitstring";
1263
    register u_char *bufp = data;
1264
    u_long          asn_length;
1265
 
1266
    *type = *bufp++;
1267
    bufp = asn_parse_length(bufp, &asn_length);
1268
    if (_asn_parse_length_check(errpre, bufp, data,
1269
               asn_length, *datalength))
1270
        return NULL;
1271
 
1272
    if ((size_t)asn_length > *strlength){
1273
        _asn_length_err(errpre, (size_t)asn_length, *strlength);
1274
        return NULL;
1275
    }
1276
    if (_asn_bitstring_check(errpre, asn_length, *bufp))
1277
        return NULL;
1278
 
1279
    DEBUGDUMPSETUP("dump_recv", data, bufp - data);
1280
    DEBUGMSG(("dump_recv", "  ASN Bitstring: "));
1281
    DEBUGMSGHEX(("dump_recv", data, asn_length));
1282
 
1283
    memmove(string, bufp, asn_length);
1284
    *strlength = (int)asn_length;
1285
    *datalength -= (int)asn_length + (bufp - data);
1286
    return bufp + asn_length;
1287
}
1288
 
1289
 
1290
/*
1291
 * asn_build_bitstring - Builds an ASN bit string object containing the
1292
 * input string.
1293
 *  On entry, datalength is input as the number of valid bytes following
1294
 *   "data".  On exit, it is returned as the number of valid bytes
1295
 *   following the beginning of the next object.
1296
 *
1297
 *  Returns a pointer to the first byte past the end
1298
 *   of this object (i.e. the start of the next object).
1299
 *  Returns NULL on any error.
1300
 
1301
  u_char * asn_build_bitstring(
1302
      u_char     *data         IN - pointer to start of object
1303
      int        *datalength   IN/OUT - number of valid bytes left in buffer
1304
      u_char      type         IN - asn type of object
1305
      u_char     *string       IN - pointer to start of input buffer
1306
      int         strlength    IN - size of input buffer
1307
 */
1308
u_char *
1309
asn_build_bitstring(u_char *data,
1310
                    size_t *datalength,
1311
                    u_char type,
1312
                    u_char *string,
1313
                    size_t strlength)
1314
{
1315
/*
1316
 * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
1317
 */
1318
    static const char *errpre = "build bitstring";
1319
    if (_asn_bitstring_check(errpre, strlength, *string))
1320
        return NULL;
1321
 
1322
    data = asn_build_header(data, datalength, type, strlength);
1323
    if (_asn_build_header_check(errpre,data,*datalength,strlength))
1324
        return NULL;
1325
 
1326
    memmove(data, string, strlength);
1327
    *datalength -= strlength;
1328
    return data + strlength;
1329
}
1330
 
1331
 
1332
/*
1333
 * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
1334
 * type.
1335
 *  On entry, datalength is input as the number of valid bytes following
1336
 *   "data".  On exit, it is returned as the number of valid bytes
1337
 *   following the end of this object.
1338
 *
1339
 *  Returns a pointer to the first byte past the end
1340
 *   of this object (i.e. the start of the next object).
1341
 *  Returns NULL on any error.
1342
 
1343
  u_char * asn_parse_unsigned_int64(
1344
      u_char     *data         IN - pointer to start of object
1345
      int        *datalength   IN/OUT - number of valid bytes left in buffer
1346
      u_char     *type         OUT - asn type of object
1347
      struct counter64 *cp     IN/OUT - pointer to counter struct
1348
      int         countersize  IN - size of output buffer
1349
 */
1350
u_char *
1351
asn_parse_unsigned_int64(u_char *data,
1352
                         size_t *datalength,
1353
                         u_char *type,
1354
                         struct counter64 *cp,
1355
                         size_t countersize)
1356
{
1357
/*
1358
 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1359
 */
1360
    static const char *errpre = "parse uint64";
1361
    const int uint64sizelimit = (4 * 2) + 1;
1362
    register u_char *bufp = data;
1363
    u_long          asn_length;
1364
    register u_long low = 0, high = 0;
1365
 
1366
    if (countersize != sizeof(struct counter64)){
1367
        _asn_size_err(errpre, countersize, sizeof(struct counter64));
1368
        return NULL;
1369
    }
1370
    *type = *bufp++;
1371
    bufp = asn_parse_length(bufp, &asn_length);
1372
    if (_asn_parse_length_check(errpre, bufp, data, asn_length, *datalength))
1373
        return NULL;
1374
 
1375
    DEBUGDUMPSETUP("dump_recv", data, bufp - data);
1376
#ifdef OPAQUE_SPECIAL_TYPES
1377
/* 64 bit counters as opaque */
1378
    if ((*type == ASN_OPAQUE) &&
1379
            (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
1380
            (*bufp == ASN_OPAQUE_TAG1) &&
1381
            ((*(bufp+1) == ASN_OPAQUE_COUNTER64) ||
1382
             (*(bufp+1) == ASN_OPAQUE_U64))) {
1383
        DEBUGMSG(("dump_recv", "Opaque %.2x %.2x: ", *bufp, *(bufp+1)));
1384
 
1385
        /* change type to Counter64 or U64 */
1386
        *type = *(bufp+1);
1387
        /* value is encoded as special format */
1388
        bufp = asn_parse_length(bufp + 2, &asn_length);
1389
        if (_asn_parse_length_check("parse opaque uint64", bufp, data,
1390
                  asn_length, *datalength))
1391
        return NULL;
1392
    }
1393
#endif /* OPAQUE_SPECIAL_TYPES */
1394
    if (((int)asn_length > uint64sizelimit) ||
1395
        (((int)asn_length == uint64sizelimit) && *bufp != 0x00)){
1396
        _asn_length_err(errpre, (size_t)asn_length, uint64sizelimit);
1397
        return NULL;
1398
    }
1399
    *datalength -= (int)asn_length + (bufp - data);
1400
    if (*bufp & 0x80){
1401
        low = ~low; /* integer is negative */
1402
        high = ~high;
1403
    }
1404
 
1405
    while(asn_length--){
1406
        high = (high << 8) | ((low & 0xFF000000) >> 24);
1407
        low = (low << 8) | *bufp++;
1408
    }
1409
 
1410
    cp->low = low;
1411
    cp->high = high;
1412
 
1413
    DEBUGIF("dump_recv") {
1414
      char i64buf[I64CHARSZ+1];
1415
      printU64(i64buf, cp);
1416
    }
1417
 
1418
    return bufp;
1419
}
1420
 
1421
 
1422
/*
1423
 * asn_build_unsigned_int64 - builds an ASN object containing a 64 bit integer.
1424
 *  On entry, datalength is input as the number of valid bytes following
1425
 *   "data".  On exit, it is returned as the number of valid bytes
1426
 *   following the end of this object.
1427
 *
1428
 *  Returns a pointer to the first byte past the end
1429
 *   of this object (i.e. the start of the next object).
1430
 *  Returns NULL on any error.
1431
 
1432
  u_char * asn_build_unsigned_int64(
1433
      u_char     *data         IN - pointer to start of output buffer
1434
      size_t     *datalength   IN/OUT - number of valid bytes left in buffer
1435
      u_char      type         IN  - asn type of object
1436
      struct counter64 *cp     IN - pointer to counter struct
1437
      size_t      countersize  IN - size of input buffer
1438
 */
1439
u_char *
1440
asn_build_unsigned_int64(u_char *data,
1441
                         size_t *datalength,
1442
                         u_char type,
1443
                         struct counter64 *cp,
1444
                         size_t countersize)
1445
{
1446
/*
1447
 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1448
 */
1449
 
1450
    register u_long low, high;
1451
    register u_long mask, mask2;
1452
    int add_null_byte = 0;
1453
    size_t intsize;
1454
 
1455
  if (countersize != sizeof(struct counter64)){
1456
    _asn_size_err("build uint64", countersize, sizeof(struct counter64));
1457
    return NULL;
1458
  }
1459
    intsize = 8;
1460
    low = cp->low;
1461
    high = cp->high;
1462
    mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
1463
    /* mask is 0xFF000000 on a big-endian machine */
1464
    if ((u_char)((high & mask) >> (8 * (sizeof(long) - 1))) & 0x80){
1465
        /* if MSB is set */
1466
        add_null_byte = 1;
1467
        intsize++;
1468
    } else {
1469
        /*
1470
         * Truncate "unnecessary" bytes off of the most significant end of this 2's
1471
         * complement integer.
1472
         * There should be no sequence of 9 consecutive 1's or 0's at the most
1473
         * significant end of the integer.
1474
         */
1475
        mask2 = ((u_long) 0x1FF) << ((8 * (sizeof(long) - 1)) - 1);
1476
        /* mask2 is 0xFF800000 on a big-endian machine */
1477
        while((((high & mask2) == 0) || ((high & mask2) == mask2)) && intsize > 1){
1478
            intsize--;
1479
            high = (high << 8)
1480
                | ((low & mask) >> (8 * (sizeof(long) - 1)));
1481
            low <<= 8;
1482
        }
1483
    }
1484
#ifdef OPAQUE_SPECIAL_TYPES
1485
/* encode a Counter64 as an opaque (it also works in SNMPv1) */
1486
    /* turn into Opaque holding special tagged value */
1487
    if (type == ASN_OPAQUE_COUNTER64) {
1488
        /* put the tag and length for the Opaque wrapper */
1489
        data = asn_build_header(data, datalength, ASN_OPAQUE, intsize+3);
1490
    if (_asn_build_header_check("build counter u64", data, *datalength, intsize+3))
1491
        return NULL;
1492
 
1493
        /* put the special tag and length */
1494
        *data++ = ASN_OPAQUE_TAG1;
1495
        *data++ = ASN_OPAQUE_COUNTER64;
1496
        *data++ = (u_char)intsize;
1497
        *datalength = *datalength - 3;
1498
    }
1499
    else
1500
/* Encode the Unsigned int64 in an opaque */
1501
    /* turn into Opaque holding special tagged value */
1502
    if (type == ASN_OPAQUE_U64) {
1503
        /* put the tag and length for the Opaque wrapper */
1504
        data = asn_build_header(data, datalength, ASN_OPAQUE, intsize+3);
1505
    if (_asn_build_header_check("build opaque u64", data, *datalength, intsize+3))
1506
        return NULL;
1507
 
1508
        /* put the special tag and length */
1509
        *data++ = ASN_OPAQUE_TAG1;
1510
        *data++ = ASN_OPAQUE_U64;
1511
        *data++ = (u_char)intsize;
1512
        *datalength = *datalength - 3;
1513
    }
1514
    else
1515
    {
1516
#endif /* OPAQUE_SPECIAL_TYPES */
1517
    data = asn_build_header(data, datalength, type, intsize);
1518
    if (_asn_build_header_check("build uint64", data, *datalength, intsize))
1519
        return NULL;
1520
 
1521
#ifdef OPAQUE_SPECIAL_TYPES
1522
    }
1523
#endif /* OPAQUE_SPECIAL_TYPES */
1524
    *datalength -= intsize;
1525
    if (add_null_byte == 1){
1526
        *data++ = '\0';
1527
        intsize--;
1528
    }
1529
    while(intsize--){
1530
        *data++ = (u_char)((high & mask) >> (8 * (sizeof(long) - 1)));
1531
        high = (high << 8)
1532
            | ((low & mask) >> (8 * (sizeof(long) - 1)));
1533
        low <<= 8;
1534
 
1535
    }
1536
    return data;
1537
}
1538
 
1539
#ifdef OPAQUE_SPECIAL_TYPES
1540
 
1541
/*
1542
 
1543
  u_char * asn_parse_signed_int64(
1544
      u_char     *data         IN - pointer to start of object
1545
      int        *datalength   IN/OUT - number of valid bytes left in buffer
1546
      u_char     *type         OUT - asn type of object
1547
      struct counter64 *cp     IN/OUT - pointer to counter struct
1548
      int         countersize  IN - size of output buffer
1549
 */
1550
 
1551
u_char *
1552
asn_parse_signed_int64(u_char *data,
1553
                       size_t *datalength,
1554
                       u_char *type,
1555
                       struct counter64 *cp,
1556
                       size_t countersize)
1557
{
1558
  static const char *errpre = "parse int64";
1559
  const int int64sizelimit = (4 * 2) + 1;
1560
  char ebuf[128];
1561
  register u_char *bufp = data;
1562
  u_long            asn_length;
1563
  register u_int low = 0, high = 0;
1564
 
1565
  if (countersize != sizeof(struct counter64)){
1566
    _asn_size_err(errpre, countersize, sizeof(struct counter64));
1567
    return NULL;
1568
  }
1569
  *type = *bufp++;
1570
  bufp = asn_parse_length(bufp, &asn_length);
1571
  if (_asn_parse_length_check(errpre, bufp, data, asn_length, *datalength))
1572
        return NULL;
1573
 
1574
  DEBUGDUMPSETUP("dump_recv", data, bufp - data);
1575
  if ((*type == ASN_OPAQUE) &&
1576
      (asn_length <= ASN_OPAQUE_COUNTER64_MX_BER_LEN) &&
1577
      (*bufp == ASN_OPAQUE_TAG1) &&
1578
       (*(bufp+1) == ASN_OPAQUE_I64)) {
1579
      DEBUGMSG(("dump_recv", "Opaque %.2x %.2x: ", *bufp, *(bufp+1)));
1580
    /* change type to Int64 */
1581
    *type = *(bufp+1);
1582
    /* value is encoded as special format */
1583
    bufp = asn_parse_length(bufp + 2, &asn_length);
1584
    if (_asn_parse_length_check("parse opaque int64", bufp, data,
1585
                  asn_length, *datalength))
1586
        return NULL;
1587
  }
1588
  /* this should always have been true until snmp gets int64 PDU types */
1589
  else {
1590
    sprintf(ebuf, "%s: wrong type: %d, len %d, buf bytes (%02X,%02X)",
1591
             errpre, *type, (int)asn_length, *bufp, *(bufp+1));
1592
    ERROR_MSG(ebuf);
1593
    return NULL;
1594
  }
1595
  if (((int)asn_length > int64sizelimit) ||
1596
      (((int)asn_length == int64sizelimit) && *bufp != 0x00)){
1597
    _asn_length_err(errpre, (size_t)asn_length, int64sizelimit);
1598
    return NULL;
1599
  }
1600
  *datalength -= (int)asn_length + (bufp - data);
1601
  if (*bufp & 0x80){
1602
    low = ~low; /* integer is negative */
1603
    high = ~high;
1604
  }
1605
 
1606
  while(asn_length--){
1607
    high = (high << 8) | ((low & 0xFF000000) >> 24);
1608
    low = (low << 8) | *bufp++;
1609
  }
1610
 
1611
  cp->low = low;
1612
  cp->high = high;
1613
 
1614
  DEBUGIF("dump_recv") {
1615
    char i64buf[I64CHARSZ+1];
1616
    printI64(i64buf, cp);
1617
  }
1618
 
1619
  return bufp;
1620
}
1621
 
1622
 
1623
/*
1624
 
1625
  u_char * asn_build_signed_int64(
1626
      u_char     *data         IN - pointer to start of object
1627
      int        *datalength   IN/OUT - number of valid bytes left in buffer
1628
      u_char      type         IN - asn type of object
1629
      struct counter64 *cp     IN - pointer to counter struct
1630
      int         countersize  IN - size of input buffer
1631
 */
1632
u_char *
1633
asn_build_signed_int64(u_char *data,
1634
                       size_t *datalength,
1635
                       u_char type,
1636
                       struct counter64 *cp,
1637
                       size_t countersize)
1638
{
1639
/*
1640
 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1641
 */
1642
 
1643
    struct counter64 c64;
1644
    register u_int mask, mask2;
1645
    u_long low, high;
1646
    size_t intsize;
1647
 
1648
  if (countersize != sizeof(struct counter64)){
1649
    _asn_size_err("build int64", countersize, sizeof(struct counter64));
1650
    return NULL;
1651
  }
1652
    intsize = 8;
1653
    memcpy(&c64, cp, sizeof(struct counter64));  /* we're may modify it */
1654
    low = c64.low;
1655
    high = c64.high;
1656
 
1657
    /*
1658
     * Truncate "unnecessary" bytes off of the most significant end of this
1659
     * 2's complement integer.  There should be no sequence of 9
1660
     * consecutive 1's or 0's at the most significant end of the
1661
     * integer.
1662
     */
1663
    mask = ((u_int) 0xFF) << (8 * (sizeof(u_int) - 1));
1664
    mask2 = ((u_int) 0x1FF) << ((8 * (sizeof(u_int) - 1)) - 1);
1665
    /* mask is 0xFF800000 on a big-endian machine */
1666
    while((((high & mask2) == 0) || ((high & mask2) == mask2)) && intsize > 1){
1667
      intsize--;
1668
      high = (high << 8)
1669
        | ((low & mask) >> (8 * (sizeof(u_int) - 1)));
1670
      low <<= 8;
1671
    }
1672
    /* until a real int64 gets incorperated into SNMP, we are going to
1673
       encode it as an opaque instead.  First, we build the opaque
1674
       header and then the int64 tag type we use to mark it as an
1675
       int64 in the opaque string. */
1676
    data = asn_build_header(data, datalength, ASN_OPAQUE, intsize+3);
1677
    if (_asn_build_header_check("build int64", data, *datalength, intsize+3))
1678
        return NULL;
1679
 
1680
    *data++ = ASN_OPAQUE_TAG1;
1681
    *data++ = ASN_OPAQUE_I64;
1682
    *data++ = (u_char)intsize;
1683
    *datalength -= (3 + intsize);
1684
 
1685
    while(intsize--){
1686
        *data++ = (u_char)((high & mask) >> (8 * (sizeof(u_int) - 1)));
1687
        high = (high << 8)
1688
            | ((low & mask) >> (8 * (sizeof(u_int) - 1)));
1689
        low <<= 8;
1690
    }
1691
    return data;
1692
}
1693
 
1694
/*
1695
 * asn_parse_float - pulls a single precision floating-point out of an opaque type.
1696
 *
1697
 *  On entry, datalength is input as the number of valid bytes following
1698
 *   "data".  On exit, it is returned as the number of valid bytes
1699
 *   following the end of this object.
1700
 *
1701
 *  Returns a pointer to the first byte past the end
1702
 *   of this object (i.e. the start of the next object).
1703
 *  Returns NULL on any error.
1704
 
1705
  u_char * asn_parse_float(
1706
      u_char     *data         IN - pointer to start of object
1707
      int        *datalength   IN/OUT - number of valid bytes left in buffer
1708
      u_char     *type         OUT - asn type of object
1709
      float      *floatp       IN/OUT - pointer to float
1710
      int         floatsize    IN - size of output buffer
1711
 */
1712
u_char *
1713
asn_parse_float(u_char *data,
1714
                size_t *datalength,
1715
                u_char *type,
1716
                float *floatp,
1717
                size_t floatsize)
1718
{
1719
    register u_char *bufp = data;
1720
    u_long          asn_length;
1721
    union {
1722
        float  floatVal;
1723
        long   longVal;
1724
        u_char c[sizeof(float)];
1725
    } fu;
1726
 
1727
    if (floatsize != sizeof(float)){
1728
        _asn_size_err("parse float", floatsize, sizeof(float));
1729
        return NULL;
1730
    }
1731
    *type = *bufp++;
1732
    bufp = asn_parse_length(bufp, &asn_length);
1733
    if (_asn_parse_length_check("parse float", bufp, data,
1734
                  asn_length, *datalength))
1735
        return NULL;
1736
 
1737
    DEBUGDUMPSETUP("dump_recv", data, bufp - data + asn_length);
1738
/* the float is encoded as an opaque */
1739
    if ((*type == ASN_OPAQUE) &&
1740
            (asn_length == ASN_OPAQUE_FLOAT_BER_LEN) &&
1741
            (*bufp == ASN_OPAQUE_TAG1) &&
1742
            (*(bufp+1) == ASN_OPAQUE_FLOAT)) {
1743
      DEBUGMSG(("dump_recv", "Opaque %.2x %.2x: ", *bufp, *(bufp+1)));
1744
 
1745
        /* value is encoded as special format */
1746
        bufp = asn_parse_length(bufp + 2, &asn_length);
1747
        if (_asn_parse_length_check("parse opaque float", bufp, data,
1748
                  asn_length, *datalength))
1749
        return NULL;
1750
 
1751
        /* change type to Float */
1752
        *type = ASN_OPAQUE_FLOAT;
1753
    }
1754
 
1755
    if (asn_length != sizeof(float)) {
1756
        _asn_size_err("parse seq float", asn_length, sizeof(float));
1757
        return NULL;
1758
    }
1759
 
1760
    *datalength -= (int)asn_length + (bufp - data);
1761
    memcpy(&fu.c[0], bufp, asn_length);
1762
 
1763
   /* correct for endian differences */
1764
    fu.longVal = ntohl(fu.longVal);
1765
 
1766
    *floatp =  fu.floatVal;
1767
 
1768
    DEBUGMSG(("dump_recv", "%f",*floatp));
1769
    return bufp;
1770
}
1771
 
1772
/*
1773
 * asn_build_float - builds an ASN object containing a single precision floating-point
1774
 *                    number in an Opaque value.
1775
 *
1776
 *  On entry, datalength is input as the number of valid bytes following
1777
 *   "data".  On exit, it is returned as the number of valid bytes
1778
 *   following the end of this object.
1779
 *
1780
 *  Returns a pointer to the first byte past the end
1781
 *   of this object (i.e. the start of the next object).
1782
 *  Returns NULL on any error.
1783
 
1784
  u_char * asn_build_float(
1785
      u_char     *data         IN - pointer to start of object
1786
      int        *datalength   IN/OUT - number of valid bytes left in buffer
1787
      u_char      type         IN - asn type of object
1788
      float      *floatp       IN - pointer to float
1789
      int         floatsize    IN - size of input buffer
1790
 */
1791
u_char *
1792
asn_build_float(u_char *data,
1793
                size_t *datalength,
1794
                u_char type,
1795
                float *floatp,
1796
                size_t floatsize)
1797
{
1798
    union {
1799
        float  floatVal;
1800
        int    intVal;
1801
        u_char c[sizeof(float)];
1802
    } fu;
1803
 
1804
    if (floatsize != sizeof (float)) {
1805
        _asn_size_err("build float", floatsize, sizeof(float));
1806
        return NULL;
1807
    }
1808
/* encode the float as an opaque */
1809
    /* turn into Opaque holding special tagged value */
1810
 
1811
    /* put the tag and length for the Opaque wrapper */
1812
    data = asn_build_header(data, datalength, ASN_OPAQUE, floatsize+3);
1813
    if (_asn_build_header_check("build float", data, *datalength, (floatsize+3)))
1814
        return NULL;
1815
 
1816
    /* put the special tag and length */
1817
    *data++ = ASN_OPAQUE_TAG1;
1818
    *data++ = ASN_OPAQUE_FLOAT;
1819
    *data++ = (u_char)floatsize;
1820
    *datalength = *datalength - 3;
1821
 
1822
    fu.floatVal = *floatp;
1823
    /* correct for endian differences */
1824
    fu.intVal = htonl(fu.intVal);
1825
 
1826
    *datalength -= floatsize;
1827
    memcpy(data, &fu.c[0], floatsize);
1828
 
1829
    data += floatsize;
1830
    return data;
1831
}
1832
 
1833
/*
1834
 
1835
  u_char * asn_parse_double(
1836
      u_char     *data         IN - pointer to start of object
1837
      int        *datalength   IN/OUT - number of valid bytes left in buffer
1838
      u_char     *type         OUT - asn type of object
1839
      double     *doublep      IN/OUT - pointer to double
1840
      int         doublesize   IN - size of output buffer
1841
 */
1842
u_char *
1843
asn_parse_double(u_char *data,
1844
                 size_t *datalength,
1845
                 u_char *type,
1846
                 double *doublep,
1847
                 size_t doublesize)
1848
{
1849
    register u_char *bufp = data;
1850
    u_long          asn_length;
1851
    long            tmp;
1852
    union {
1853
        double doubleVal;
1854
        int    intVal[2];
1855
        u_char c[sizeof(double)];
1856
    } fu;
1857
 
1858
 
1859
    if (doublesize != sizeof(double)){
1860
        _asn_size_err("parse double", doublesize, sizeof(double));
1861
        return NULL;
1862
    }
1863
    *type = *bufp++;
1864
    bufp = asn_parse_length(bufp, &asn_length);
1865
    if (_asn_parse_length_check("parse double", bufp, data,
1866
                  asn_length, *datalength))
1867
        return NULL;
1868
 
1869
    DEBUGDUMPSETUP("dump_recv", data, bufp - data + asn_length);
1870
/* the double is encoded as an opaque */
1871
    if ((*type == ASN_OPAQUE) &&
1872
            (asn_length == ASN_OPAQUE_DOUBLE_BER_LEN) &&
1873
            (*bufp == ASN_OPAQUE_TAG1) &&
1874
            (*(bufp+1) == ASN_OPAQUE_DOUBLE)) {
1875
      DEBUGMSG(("dump_recv", "Opaque %.2x %.2x: ", *bufp, *(bufp+1)));
1876
 
1877
        /* value is encoded as special format */
1878
        bufp = asn_parse_length(bufp + 2, &asn_length);
1879
        if (_asn_parse_length_check("parse opaque double", bufp, data,
1880
                  asn_length, *datalength))
1881
        return NULL;
1882
 
1883
        /* change type to Double */
1884
        *type = ASN_OPAQUE_DOUBLE;
1885
    }
1886
 
1887
    if (asn_length != sizeof(double)) {
1888
        _asn_size_err("parse seq double", asn_length, sizeof(double));
1889
        return NULL;
1890
    }
1891
    *datalength -= (int)asn_length + (bufp - data);
1892
    memcpy(&fu.c[0], bufp, asn_length);
1893
 
1894
   /* correct for endian differences */
1895
 
1896
    tmp = ntohl(fu.intVal[0]);
1897
    fu.intVal[0] = ntohl(fu.intVal[1]);
1898
    fu.intVal[1] = tmp;
1899
 
1900
    *doublep =  fu.doubleVal;
1901
    DEBUGMSG(("dump_recv", "%d",*doublep));
1902
 
1903
    return bufp;
1904
}
1905
 
1906
/*
1907
 
1908
  u_char * asn_build_double(
1909
      u_char     *data         IN - pointer to start of object
1910
      int        *datalength   IN/OUT - number of valid bytes left in buffer
1911
      u_char      type         IN - asn type of object
1912
      double     *doublep      IN - pointer to double
1913
      int         doublesize   IN - size of input buffer
1914
 */
1915
u_char *
1916
asn_build_double(u_char *data,
1917
                 size_t *datalength,
1918
                 u_char type,
1919
                 double* doublep,
1920
                 size_t doublesize)
1921
{
1922
    long  tmp;
1923
    union {
1924
        double doubleVal;
1925
        int    intVal[2];
1926
        u_char c[sizeof(double)];
1927
    } fu;
1928
 
1929
    if (doublesize != sizeof(double)){
1930
        _asn_size_err("build double", doublesize, sizeof(double));
1931
        return NULL;
1932
    }
1933
 
1934
/* encode the double as an opaque */
1935
    /* turn into Opaque holding special tagged value */
1936
 
1937
    /* put the tag and length for the Opaque wrapper */
1938
    data = asn_build_header(data, datalength, ASN_OPAQUE, doublesize+3);
1939
    if (_asn_build_header_check("build double", data, *datalength, doublesize+3))
1940
        return NULL;
1941
 
1942
    /* put the special tag and length */
1943
    *data++ = ASN_OPAQUE_TAG1;
1944
    *data++ = ASN_OPAQUE_DOUBLE;
1945
    *data++ = (u_char)doublesize;
1946
    *datalength = *datalength - 3;
1947
 
1948
    fu.doubleVal = *doublep;
1949
    /* correct for endian differences */
1950
    tmp = htonl(fu.intVal[0]);
1951
    fu.intVal[0] = htonl(fu.intVal[1]);
1952
    fu.intVal[1] = tmp;
1953
    *datalength -= doublesize;
1954
    memcpy(data, &fu.c[0], doublesize);
1955
 
1956
    data += doublesize;
1957
    return data;
1958
}
1959
 
1960
#endif /* OPAQUE_SPECIAL_TYPES */
1961
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.