]> git.karo-electronics.de Git - karo-tx-redboot.git/blob - packages/net/snmp/lib/v2_0/src/asn1.c
Initial revision
[karo-tx-redboot.git] / packages / net / snmp / lib / v2_0 / src / asn1.c
1 //==========================================================================
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