1 //==========================================================================
3 // ./lib/current/src/asn1.c
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.
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.
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
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.
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.
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.
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####
41 // -------------------------------------------
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.
49 // The release used was version 4.1.2 of May 2000. "ucd-snmp-4.1.2"
50 // -------------------------------------------
52 //####UCDSNMPCOPYRIGHTEND####
53 //==========================================================================
54 //#####DESCRIPTIONBEGIN####
59 // Purpose: Port of UCD-SNMP distribution to eCos.
63 //####DESCRIPTIONEND####
65 //==========================================================================
66 /********************************************************************
67 Copyright 1989, 1991, 1992 by Carnegie Mellon University
70 Copyright 1996, 1998, 1999, 2000 The Regents of the University of California
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
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 *********************************************************************/
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.
98 * Encodes abstract data types into a machine independent stream of bytes.
101 /**********************************************************************
102 Copyright 1988, 1989, 1991, 1992 by Carnegie Mellon University
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.
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
121 ******************************************************************/
134 #include <sys/types.h>
142 #if HAVE_NETINET_IN_H
143 #include <netinet/in.h>
156 #include "snmp_debug.h"
163 #include "snmp_api.h"
164 #include "snmp_impl.h" /* to define ERROR_MSG */
167 void _asn_size_err(const char *str, size_t wrongsize, size_t rightsize)
171 sprintf(ebuf,"%s size %d: s/b %d",str, wrongsize, rightsize);
176 void _asn_length_err(const char *str, size_t wrongsize, size_t rightsize)
180 sprintf(ebuf,"%s length %d too large: exceeds %d",str, wrongsize, rightsize);
185 * call after asn_parse_length to verify result.
188 int _asn_parse_length_check(const char *str,
189 u_char *bufp, u_char *data,
190 u_long plen, size_t dlen)
196 /* error message is set */
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);
210 * call after asn_build_header to verify result.
213 int _asn_build_header_check(const char *str, u_char *data,
214 size_t datalen, size_t typedlen)
219 /* error message is set */
222 if (datalen < typedlen){
223 sprintf(ebuf, "%s: bad header, length too short: %d < %d", str, datalen, typedlen);
230 /* checks the incoming packet for validity and returns its size or 0 */
232 asn_check_packet (u_char *pkt, size_t len)
237 return 0; /* always too short */
239 if (*pkt != (u_char)(ASN_SEQUENCE | ASN_CONSTRUCTOR))
240 return -1; /* wrong type */
242 if (*(pkt+1) & 0x80) {
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));
250 return (*(pkt+1) + 2);
255 int _asn_bitstring_check(const char * str, u_long asn_length, u_char datum)
260 sprintf(ebuf,"%s: length %d too small", str, (int)asn_length);
265 sprintf(ebuf,"%s: datum %d >7: too large", str, (int)(datum));
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.
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.
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
291 asn_parse_int(u_char *data,
298 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
300 static const char *errpre = "parse int";
301 register u_char *bufp = data;
303 register long value = 0;
305 if (intsize != sizeof (long)){
306 _asn_size_err(errpre, intsize, sizeof(long));
310 bufp = asn_parse_length(bufp, &asn_length);
311 if (_asn_parse_length_check(errpre, bufp, data, asn_length, *datalength))
314 if ((size_t)asn_length > intsize){
315 _asn_length_err(errpre, (size_t)asn_length, intsize);
319 *datalength -= (int)asn_length + (bufp - data);
321 value = -1; /* integer is negative */
323 DEBUGDUMPSETUP("dump_recv", data, bufp - data + asn_length);
326 value = (value << 8) | *bufp++;
328 DEBUGMSG(("dump_recv", " ASN Integer:\t%ld (0x%.2X)\n", value, value));
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.
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.
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
353 asn_parse_unsigned_int(u_char *data,
360 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
362 static const char *errpre = "parse uint";
363 register u_char *bufp = data;
365 register u_long value = 0;
367 if (intsize != sizeof (long)){
368 _asn_size_err(errpre, intsize, sizeof(long));
372 bufp = asn_parse_length(bufp, &asn_length);
373 if (_asn_parse_length_check(errpre, bufp, data, asn_length, *datalength))
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);
381 *datalength -= (int)asn_length + (bufp - data);
383 value = ~value; /* integer is negative */
385 DEBUGDUMPSETUP("dump_recv", data, bufp - data + asn_length);
388 value = (value << 8) | *bufp++;
390 DEBUGMSG(("dump_recv", " ASN UInteger:\t%ld (0x%.2X)\n", value, value));
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.
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.
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
415 asn_build_int(u_char *data,
422 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
424 static const char *errpre = "build int";
425 register long integer;
426 register u_long mask;
428 if (intsize != sizeof (long)){
429 _asn_size_err(errpre, intsize, sizeof(long));
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
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))
446 data = asn_build_header(data, datalength, type, intsize);
447 if (_asn_build_header_check(errpre,data,*datalength,intsize))
450 *datalength -= intsize;
451 mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
452 /* mask is 0xFF000000 on a big-endian machine */
454 *data++ = (u_char)((integer & mask) >> (8 * (sizeof(long) - 1)));
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.
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.
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
479 asn_build_unsigned_int(u_char *data,
486 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
488 static const char *errpre = "build uint";
489 register u_long integer;
490 register u_long mask;
491 int add_null_byte = 0;
493 if (intsize != sizeof (long)){
494 _asn_size_err(errpre, intsize, sizeof(long));
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){
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
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){
517 data = asn_build_header(data, datalength, type, intsize);
518 if (_asn_build_header_check(errpre,data,*datalength,intsize))
521 *datalength -= intsize;
522 if (add_null_byte == 1){
526 mask = ((u_long) 0xFF) << (8 * (sizeof(long) - 1));
527 /* mask is 0xFF000000 on a big-endian machine */
529 *data++ = (u_char)((integer & mask) >> (8 * (sizeof(long) - 1)));
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.
542 * "string" is filled with the octet string.
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.
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
556 * ASN.1 octet string ::= primstring | cmpdstring
557 * primstring ::= 0x04 asnlength byte {byte}*
558 * cmpdstring ::= 0x24 asnlength string {string}*
561 asn_parse_string(u_char *data,
567 static const char *errpre = "parse string";
572 bufp = asn_parse_length(bufp, &asn_length);
573 if (_asn_parse_length_check(errpre, bufp, data, asn_length, *datalength))
576 if ((int)asn_length > *strlength){
577 _asn_length_err(errpre, (size_t)asn_length, *strlength);
581 DEBUGDUMPSETUP("dump_recv", data, bufp - data + asn_length);
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);
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));
596 return bufp + asn_length;
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.
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.
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
618 asn_build_string(u_char *data,
621 const u_char *string,
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.
630 data = asn_build_header(data, datalength, type, strlength);
631 if (_asn_build_header_check("build string", data, *datalength, strlength))
635 if (string == NULL) {
636 memset(data, 0, strlength);
638 memmove(data, string, strlength);
641 *datalength -= strlength;
642 return data + strlength;
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.
653 * Returns a pointer to the first byte of the contents of this object.
654 * Returns NULL on any error.
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
662 asn_parse_header(u_char *data,
666 register u_char *bufp;
669 if (!data || !datalength || !type) {
670 ERROR_MSG("parse header: NULL pointer");
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");
680 bufp = asn_parse_length(bufp + 1, &asn_length);
681 if (_asn_parse_length_check("parse header", bufp, data, asn_length, *datalength))
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));
688 #ifdef OPAQUE_SPECIAL_TYPES
690 if ((*type == ASN_OPAQUE) &&
691 (*bufp == ASN_OPAQUE_TAG1)) {
693 DEBUGDUMPSETUP("dump_recv", data, 1);
694 DEBUGMSG(("dump_recv", "Opaque:\t%.2x\n", *bufp));
697 /* check if 64-but counter */
699 case ASN_OPAQUE_COUNTER64:
701 case ASN_OPAQUE_FLOAT:
702 case ASN_OPAQUE_DOUBLE:
709 *datalength = (int)asn_length;
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))
718 #endif /* OPAQUE_SPECIAL_TYPES */
720 *datalength = (int)asn_length;
726 * same as asn_parse_header with test for expected type.
729 asn_parse_sequence(u_char *data,
732 u_char expected_type, /* must be this type */
733 const char *estr) /* error message prefix */
735 data = asn_parse_header(data, datalength, type);
736 if (data && (*type != expected_type)) {
738 sprintf(ebuf, "%s header type %02X: s/b %02X", estr,
739 (u_char)*type, (u_char)expected_type);
749 * asn_build_header - builds an ASN header for an object with the ID and
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.
755 * This only works on data types < 30, i.e. no extension octets.
756 * The maximum length is 0xFFFF;
758 * Returns a pointer to the first byte of the contents of this object.
759 * Returns NULL on any error.
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
768 asn_build_header (u_char *data,
775 if (*datalength < 1){
776 sprintf(ebuf, "bad header length < 1 :%d, %d", *datalength, length);
782 return asn_build_length(data, datalength, length);
786 * asn_build_sequence - builds an ASN header for a sequence with the ID and
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.
792 * This only works on data types < 30, i.e. no extension octets.
793 * The maximum length is 0xFFFF;
795 * Returns a pointer to the first byte of the contents of this object.
796 * Returns NULL on any error.
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
805 asn_build_sequence(u_char *data,
810 static const char *errpre = "build seq";
813 if (*datalength < 4){
814 sprintf(ebuf, "%s: length %d < 4: PUNT", errpre, (int)*datalength);
820 *data++ = (u_char)(0x02 | ASN_LONG_LEN);
821 *data++ = (u_char)((length >> 8) & 0xFF);
822 *data++ = (u_char)(length & 0xFF);
827 * asn_parse_length - interprets the length of the current object.
828 * On exit, length contains the value of this length field.
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.
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
839 asn_parse_length(u_char *data,
842 static const char *errpre = "parse length";
844 register u_char lengthbyte;
846 if (!data || !length) {
847 ERROR_MSG("parse length: NULL pointer");
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);
859 if (lengthbyte > sizeof(long)){
860 sprintf(ebuf, "%s: data length %d > %d not supported", errpre,
861 lengthbyte, sizeof(long));
866 *length = 0; /* protect against short lengths */
867 while(lengthbyte--) {
872 } else { /* short asnlength */
873 *length = (long)lengthbyte;
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
886 asn_build_length(u_char *data,
890 static const char *errpre = "build length";
893 u_char *start_data = data;
895 /* no indefinite lengths sent */
897 if (*datalength < 1){
898 sprintf(ebuf, "%s: bad length < 1 :%d, %d",errpre,*datalength,length);
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);
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);
917 *data++ = (u_char)(0x02 | ASN_LONG_LEN);
918 *data++ = (u_char)((length >> 8) & 0xFF);
919 *data++ = (u_char)(length & 0xFF);
921 *datalength -= (data - start_data);
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.
932 * "objid" is filled with the object identifier.
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.
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
946 asn_parse_objid(u_char *data,
953 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
954 * subidentifier ::= {leadingbyte}* lastbyte
955 * leadingbyte ::= 1 7bitvalue
956 * lastbyte ::= 0 7bitvalue
958 register u_char *bufp = data;
959 register oid *oidp = objid + 1;
960 register u_long subidentifier;
961 register long length;
965 bufp = asn_parse_length(bufp, &asn_length);
966 if (_asn_parse_length_check("parse objid", bufp, data,
967 asn_length, *datalength))
970 *datalength -= (int)asn_length + (bufp - data);
972 DEBUGDUMPSETUP("dump_recv", data, bufp - data + asn_length);
974 /* Handle invalid object identifier encodings of the form 06 00 robustly */
976 objid[0] = objid[1] = 0;
979 (*objidlength)--; /* account for expansion of first byte */
981 while (length > 0 && (*objidlength)-- > 0){
983 do { /* shift and add in low order 7 bits */
984 subidentifier = (subidentifier << 7) + (*(u_char *)bufp & ~ASN_BIT8);
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");
993 *oidp++ = (oid)subidentifier;
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.
1002 subidentifier = (u_long)objid[1];
1003 if (subidentifier == 0x2B){
1007 if (subidentifier < 40) {
1009 objid[1] = subidentifier;
1010 } else if (subidentifier < 80) {
1012 objid[1] = subidentifier - 40;
1013 } else if (subidentifier < 120) {
1015 objid[1] = subidentifier - 80;
1017 objid[1] = (subidentifier % 40);
1018 objid[0] = ((subidentifier - objid[1]) / 40);
1022 *objidlength = (int)(oidp - objid);
1024 DEBUGMSG(("dump_recv", " ASN ObjID: "));
1025 DEBUGMSGOID(("dump_recv", objid, *objidlength));
1026 DEBUGMSG(("dump_recv", "\n"));
1031 * asn_build_objid - Builds an ASN object identifier object containing the
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.
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.
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
1049 asn_build_objid(u_char *data,
1056 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
1057 * subidentifier ::= {leadingbyte}* lastbyte
1058 * leadingbyte ::= 1 7bitvalue
1059 * lastbyte ::= 0 7bitvalue
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;
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 */
1073 } else if (objidlength == 1){
1074 /* encode the first value */
1075 objid_val = (op[0] * 40);
1079 /* combine the first two values */
1081 ERROR_MSG("build objid: bad second subidentifier");
1084 objid_val = (op[0] * 40) + op[1];
1087 first_objid_val = objid_val;
1089 /* calculate the number of bytes needed to store the encoded value */
1090 for (i = 1, asnlength = 0;;) {
1091 if (objid_val < (unsigned)0x80) {
1094 } else if (objid_val < (unsigned)0x4000) {
1097 } else if (objid_val < (unsigned)0x200000) {
1100 } else if (objid_val < (unsigned)0x10000000) {
1108 if (i >= (int)objidlength)
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))
1118 /* store the encoded OID value */
1119 for (i = 1, objid_val = first_objid_val, op = objid+2;
1120 i < (int)objidlength;
1122 if (i != 1) objid_val = *op++;
1123 switch (objid_size[i]) {
1125 *data++ = (u_char)objid_val;
1129 *data++ = (u_char)((objid_val>>7) | 0x80);
1130 *data++ = (u_char)(objid_val & 0x07f);
1134 *data++ = (u_char)((objid_val>>14) | 0x80);
1135 *data++ = (u_char)((objid_val>>7 & 0x7f) | 0x80);
1136 *data++ = (u_char)(objid_val & 0x07f);
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);
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);
1156 /* return the length and data ptr */
1157 *datalength -= asnlength;
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.
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.
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
1177 asn_parse_null(u_char *data,
1182 * ASN.1 null ::= 0x05 0x00
1184 register u_char *bufp = data;
1188 bufp = asn_parse_length(bufp, &asn_length);
1190 ERROR_MSG("parse null: bad length");
1193 if (asn_length != 0){
1194 ERROR_MSG("parse null: malformed ASN.1 null");
1198 *datalength -= (bufp - data);
1200 DEBUGDUMPSETUP("dump_recv", data, bufp - data);
1201 DEBUGMSG(("dump_recv", " ASN NULL\n"));
1203 return bufp + asn_length;
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.
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.
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
1223 asn_build_null(u_char *data,
1228 * ASN.1 null ::= 0x05 0x00
1230 return asn_build_header(data, datalength, type, 0);
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.
1239 * "string" is filled with the bit string.
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.
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
1253 asn_parse_bitstring(u_char *data,
1260 * bitstring ::= 0x03 asnlength unused {byte}*
1262 static const char *errpre = "parse bitstring";
1263 register u_char *bufp = data;
1267 bufp = asn_parse_length(bufp, &asn_length);
1268 if (_asn_parse_length_check(errpre, bufp, data,
1269 asn_length, *datalength))
1272 if ((size_t)asn_length > *strlength){
1273 _asn_length_err(errpre, (size_t)asn_length, *strlength);
1276 if (_asn_bitstring_check(errpre, asn_length, *bufp))
1279 DEBUGDUMPSETUP("dump_recv", data, bufp - data);
1280 DEBUGMSG(("dump_recv", " ASN Bitstring: "));
1281 DEBUGMSGHEX(("dump_recv", data, asn_length));
1283 memmove(string, bufp, asn_length);
1284 *strlength = (int)asn_length;
1285 *datalength -= (int)asn_length + (bufp - data);
1286 return bufp + asn_length;
1291 * asn_build_bitstring - Builds an ASN bit string object containing the
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.
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.
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
1309 asn_build_bitstring(u_char *data,
1316 * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
1318 static const char *errpre = "build bitstring";
1319 if (_asn_bitstring_check(errpre, strlength, *string))
1322 data = asn_build_header(data, datalength, type, strlength);
1323 if (_asn_build_header_check(errpre,data,*datalength,strlength))
1326 memmove(data, string, strlength);
1327 *datalength -= strlength;
1328 return data + strlength;
1333 * asn_parse_unsigned_int64 - pulls a 64 bit unsigned long out of an ASN int
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.
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.
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
1351 asn_parse_unsigned_int64(u_char *data,
1354 struct counter64 *cp,
1358 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1360 static const char *errpre = "parse uint64";
1361 const int uint64sizelimit = (4 * 2) + 1;
1362 register u_char *bufp = data;
1364 register u_long low = 0, high = 0;
1366 if (countersize != sizeof(struct counter64)){
1367 _asn_size_err(errpre, countersize, sizeof(struct counter64));
1371 bufp = asn_parse_length(bufp, &asn_length);
1372 if (_asn_parse_length_check(errpre, bufp, data, asn_length, *datalength))
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)));
1385 /* change type to Counter64 or U64 */
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))
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);
1399 *datalength -= (int)asn_length + (bufp - data);
1401 low = ~low; /* integer is negative */
1405 while(asn_length--){
1406 high = (high << 8) | ((low & 0xFF000000) >> 24);
1407 low = (low << 8) | *bufp++;
1413 DEBUGIF("dump_recv") {
1414 char i64buf[I64CHARSZ+1];
1415 printU64(i64buf, cp);
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.
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.
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
1440 asn_build_unsigned_int64(u_char *data,
1443 struct counter64 *cp,
1447 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1450 register u_long low, high;
1451 register u_long mask, mask2;
1452 int add_null_byte = 0;
1455 if (countersize != sizeof(struct counter64)){
1456 _asn_size_err("build uint64", countersize, sizeof(struct counter64));
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){
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.
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){
1480 | ((low & mask) >> (8 * (sizeof(long) - 1)));
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))
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;
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))
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;
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))
1521 #ifdef OPAQUE_SPECIAL_TYPES
1523 #endif /* OPAQUE_SPECIAL_TYPES */
1524 *datalength -= intsize;
1525 if (add_null_byte == 1){
1530 *data++ = (u_char)((high & mask) >> (8 * (sizeof(long) - 1)));
1532 | ((low & mask) >> (8 * (sizeof(long) - 1)));
1539 #ifdef OPAQUE_SPECIAL_TYPES
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
1552 asn_parse_signed_int64(u_char *data,
1555 struct counter64 *cp,
1558 static const char *errpre = "parse int64";
1559 const int int64sizelimit = (4 * 2) + 1;
1561 register u_char *bufp = data;
1563 register u_int low = 0, high = 0;
1565 if (countersize != sizeof(struct counter64)){
1566 _asn_size_err(errpre, countersize, sizeof(struct counter64));
1570 bufp = asn_parse_length(bufp, &asn_length);
1571 if (_asn_parse_length_check(errpre, bufp, data, asn_length, *datalength))
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 */
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))
1588 /* this should always have been true until snmp gets int64 PDU types */
1590 sprintf(ebuf, "%s: wrong type: %d, len %d, buf bytes (%02X,%02X)",
1591 errpre, *type, (int)asn_length, *bufp, *(bufp+1));
1595 if (((int)asn_length > int64sizelimit) ||
1596 (((int)asn_length == int64sizelimit) && *bufp != 0x00)){
1597 _asn_length_err(errpre, (size_t)asn_length, int64sizelimit);
1600 *datalength -= (int)asn_length + (bufp - data);
1602 low = ~low; /* integer is negative */
1606 while(asn_length--){
1607 high = (high << 8) | ((low & 0xFF000000) >> 24);
1608 low = (low << 8) | *bufp++;
1614 DEBUGIF("dump_recv") {
1615 char i64buf[I64CHARSZ+1];
1616 printI64(i64buf, cp);
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
1633 asn_build_signed_int64(u_char *data,
1636 struct counter64 *cp,
1640 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
1643 struct counter64 c64;
1644 register u_int mask, mask2;
1648 if (countersize != sizeof(struct counter64)){
1649 _asn_size_err("build int64", countersize, sizeof(struct counter64));
1653 memcpy(&c64, cp, sizeof(struct counter64)); /* we're may modify it */
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
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){
1669 | ((low & mask) >> (8 * (sizeof(u_int) - 1)));
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))
1680 *data++ = ASN_OPAQUE_TAG1;
1681 *data++ = ASN_OPAQUE_I64;
1682 *data++ = (u_char)intsize;
1683 *datalength -= (3 + intsize);
1686 *data++ = (u_char)((high & mask) >> (8 * (sizeof(u_int) - 1)));
1688 | ((low & mask) >> (8 * (sizeof(u_int) - 1)));
1695 * asn_parse_float - pulls a single precision floating-point out of an opaque type.
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.
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.
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
1713 asn_parse_float(u_char *data,
1719 register u_char *bufp = data;
1724 u_char c[sizeof(float)];
1727 if (floatsize != sizeof(float)){
1728 _asn_size_err("parse float", floatsize, sizeof(float));
1732 bufp = asn_parse_length(bufp, &asn_length);
1733 if (_asn_parse_length_check("parse float", bufp, data,
1734 asn_length, *datalength))
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)));
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))
1751 /* change type to Float */
1752 *type = ASN_OPAQUE_FLOAT;
1755 if (asn_length != sizeof(float)) {
1756 _asn_size_err("parse seq float", asn_length, sizeof(float));
1760 *datalength -= (int)asn_length + (bufp - data);
1761 memcpy(&fu.c[0], bufp, asn_length);
1763 /* correct for endian differences */
1764 fu.longVal = ntohl(fu.longVal);
1766 *floatp = fu.floatVal;
1768 DEBUGMSG(("dump_recv", "%f",*floatp));
1773 * asn_build_float - builds an ASN object containing a single precision floating-point
1774 * number in an Opaque value.
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.
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.
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
1792 asn_build_float(u_char *data,
1801 u_char c[sizeof(float)];
1804 if (floatsize != sizeof (float)) {
1805 _asn_size_err("build float", floatsize, sizeof(float));
1808 /* encode the float as an opaque */
1809 /* turn into Opaque holding special tagged value */
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)))
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;
1822 fu.floatVal = *floatp;
1823 /* correct for endian differences */
1824 fu.intVal = htonl(fu.intVal);
1826 *datalength -= floatsize;
1827 memcpy(data, &fu.c[0], floatsize);
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
1843 asn_parse_double(u_char *data,
1849 register u_char *bufp = data;
1855 u_char c[sizeof(double)];
1859 if (doublesize != sizeof(double)){
1860 _asn_size_err("parse double", doublesize, sizeof(double));
1864 bufp = asn_parse_length(bufp, &asn_length);
1865 if (_asn_parse_length_check("parse double", bufp, data,
1866 asn_length, *datalength))
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)));
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))
1883 /* change type to Double */
1884 *type = ASN_OPAQUE_DOUBLE;
1887 if (asn_length != sizeof(double)) {
1888 _asn_size_err("parse seq double", asn_length, sizeof(double));
1891 *datalength -= (int)asn_length + (bufp - data);
1892 memcpy(&fu.c[0], bufp, asn_length);
1894 /* correct for endian differences */
1896 tmp = ntohl(fu.intVal[0]);
1897 fu.intVal[0] = ntohl(fu.intVal[1]);
1900 *doublep = fu.doubleVal;
1901 DEBUGMSG(("dump_recv", "%d",*doublep));
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
1916 asn_build_double(u_char *data,
1926 u_char c[sizeof(double)];
1929 if (doublesize != sizeof(double)){
1930 _asn_size_err("build double", doublesize, sizeof(double));
1934 /* encode the double as an opaque */
1935 /* turn into Opaque holding special tagged value */
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))
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;
1948 fu.doubleVal = *doublep;
1949 /* correct for endian differences */
1950 tmp = htonl(fu.intVal[0]);
1951 fu.intVal[0] = htonl(fu.intVal[1]);
1953 *datalength -= doublesize;
1954 memcpy(data, &fu.c[0], doublesize);
1960 #endif /* OPAQUE_SPECIAL_TYPES */