asn1.c
上传用户:cxs890
上传日期:2021-05-22
资源大小:347k
文件大小:56k
源码类别:

SNMP编程

开发平台:

C/C++

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