asn1.c
上传用户:liugui
上传日期:2007-01-04
资源大小:822k
文件大小:31k
源码类别:

代理服务器

开发平台:

Unix_Linux

  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.  *
  12.  *           Copyright 1997 by Carnegie Mellon University
  13.  * 
  14.  *                       All Rights Reserved
  15.  * 
  16.  * Permission to use, copy, modify, and distribute this software and its
  17.  * documentation for any purpose and without fee is hereby granted,
  18.  * provided that the above copyright notice appear in all copies and that
  19.  * both that copyright notice and this permission notice appear in
  20.  * supporting documentation, and that the name of CMU not be
  21.  * used in advertising or publicity pertaining to distribution of the
  22.  * software without specific, written prior permission.
  23.  * 
  24.  * CMU DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
  25.  * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
  26.  * CMU BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
  27.  * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
  28.  * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
  29.  * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
  30.  * SOFTWARE.
  31.  * 
  32.  ***************************************************************************/
  33. #include "config.h"
  34. #include <stdio.h>
  35. #if HAVE_UNISTD_H
  36. #include <unistd.h>
  37. #endif
  38. #if HAVE_STDLIB_H
  39. #include <stdlib.h>
  40. #endif
  41. #if HAVE_SYS_TYPES_H
  42. #include <sys/types.h>
  43. #endif
  44. #if HAVE_CTYPE_H
  45. #include <ctype.h>
  46. #endif
  47. #if HAVE_GNUMALLOC_H
  48. #include <gnumalloc.h>
  49. #elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
  50. #include <malloc.h>
  51. #endif
  52. #if HAVE_MEMORY_H
  53. #include <memory.h>
  54. #endif
  55. #ifdef HAVE_STRING_H
  56. #include <string.h>
  57. #endif
  58. #ifdef HAVE_STRINGS_H
  59. #include <strings.h>
  60. #endif
  61. #if HAVE_BSTRING_H
  62. #include <bstring.h>
  63. #endif
  64. #if HAVE_SYS_SOCKET_H
  65. #include <sys/socket.h>
  66. #endif
  67. #if HAVE_NETINET_IN_H
  68. #include <netinet/in.h>
  69. #endif
  70. #if HAVE_ARPA_INET_H
  71. #include <arpa/inet.h>
  72. #endif
  73. #if HAVE_SYS_TIME_H
  74. #include <sys/time.h>
  75. #endif
  76. #if HAVE_NETDB_H
  77. #include <netdb.h>
  78. #endif
  79. #include "asn1.h"
  80. #include "snmp_api_error.h"
  81. u_char *
  82. asn_build_header(u_char * data, /* IN - ptr to start of object */
  83.     int *datalength, /* IN/OUT - # of valid bytes */
  84.      /*          left in buffer */
  85.     u_char type, /* IN - ASN type of object */
  86.     int length)
  87. { /* IN - length of object */
  88.     /* Truth is 0 'cause we don't know yet */
  89.     return (asn_build_header_with_truth(data, datalength, type, length, 0));
  90. }
  91. /*
  92.  * asn_parse_int - pulls an int out of an ASN int type.
  93.  *  On entry, datalength is input as the number of valid bytes following
  94.  *   "data".  On exit, it is returned as the number of valid bytes
  95.  *   following the end of this object.
  96.  *
  97.  *  Returns a pointer to the first byte past the end
  98.  *   of this object (i.e. the start of the next object).
  99.  *  Returns NULL on any error.
  100.  */
  101. u_char *
  102. asn_parse_int(u_char * data, int *datalength,
  103.     u_char * type, int *intp, int intsize)
  104.   /*    u_char *data;        IN     - pointer to start of object */
  105.   /*    int    *datalength;  IN/OUT - # of valid bytes left in buffer */
  106.   /*    u_char *type;        OUT    - asn type of object */
  107.   /*    int   *intp;         IN/OUT - pointer to start of output buffer */
  108.   /*    int     intsize;     IN     - size of output buffer */
  109. {
  110.     /*
  111.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  112.      */
  113.     u_char *bufp = data;
  114.     u_int asn_length;
  115.     int value = 0;
  116.     /* Room to store int? */
  117.     if (intsize != sizeof(int)) {
  118. snmp_set_api_error(SNMPERR_ASN_DECODE);
  119. return (NULL);
  120.     }
  121.     /* Type */
  122.     *type = *bufp++;
  123.     /* Extract length */
  124.     bufp = asn_parse_length(bufp, &asn_length);
  125.     if (bufp == NULL)
  126. return (NULL);
  127.     /* Make sure the entire int is in the buffer */
  128.     if (asn_length + (bufp - data) > *datalength) {
  129. snmp_set_api_error(SNMPERR_ASN_DECODE);
  130. return (NULL);
  131.     }
  132.     /* Can we store this int? */
  133.     if (asn_length > intsize) {
  134. snmp_set_api_error(SNMPERR_ASN_DECODE);
  135. return (NULL);
  136.     }
  137.     /* Remaining data */
  138.     *datalength -= (int) asn_length + (bufp - data);
  139.     /* Is the int negative? */
  140.     if (*bufp & 0x80)
  141. value = -1; /* integer is negative */
  142.     /* Extract the bytes */
  143.     while (asn_length--)
  144. value = (value << 8) | *bufp++;
  145.     /* That's it! */
  146.     *intp = value;
  147.     return (bufp);
  148. }
  149. /*
  150.  * asn_parse_unsigned_int - pulls an unsigned int out of an ASN int type.
  151.  *  On entry, datalength is input as the number of valid bytes following
  152.  *   "data".  On exit, it is returned as the number of valid bytes
  153.  *   following the end of this object.
  154.  *
  155.  *  Returns a pointer to the first byte past the end
  156.  *   of this object (i.e. the start of the next object).
  157.  *  Returns NULL on any error.
  158.  */
  159. u_char *
  160. asn_parse_unsigned_int(u_char * data, int *datalength,
  161.     u_char * type, u_int * intp, int intsize)
  162.   /*    u_char *data;          IN     - pointer to start of object */
  163.   /*    int    *datalength;    IN/OUT - # of valid bytes left in buffer */
  164.   /*    u_char *type;          OUT    - asn type of object */
  165.   /*    u_int *intp;           IN/OUT - pointer to start of output buffer */
  166.   /*    int     intsize;       IN     - size of output buffer */
  167. {
  168.     /*
  169.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  170.      */
  171.     u_char *bufp = data;
  172.     u_int asn_length;
  173.     int value = 0;
  174.     /* Room to store int? */
  175.     if (intsize != sizeof(int)) {
  176. snmp_set_api_error(SNMPERR_ASN_DECODE);
  177. return (NULL);
  178.     }
  179.     /* Type */
  180.     *type = *bufp++;
  181.     /* Extract length */
  182.     bufp = asn_parse_length(bufp, &asn_length);
  183.     if (bufp == NULL)
  184. return (NULL);
  185.     /* Make sure the entire int is in the buffer */
  186.     if (asn_length + (bufp - data) > *datalength) {
  187. snmp_set_api_error(SNMPERR_ASN_DECODE);
  188. return (NULL);
  189.     }
  190.     /* Can we store this int? */
  191.     if ((asn_length > (intsize + 1)) ||
  192. ((asn_length == intsize + 1) && *bufp != 0x00)) {
  193. snmp_set_api_error(SNMPERR_ASN_DECODE);
  194. return (NULL);
  195.     }
  196.     /* Remaining data */
  197.     *datalength -= (int) asn_length + (bufp - data);
  198.     /* Is the int negative? */
  199.     if (*bufp & 0x80)
  200. value = -1; /* integer is negative */
  201.     /* Extract the bytes */
  202.     while (asn_length--)
  203. value = (value << 8) | *bufp++;
  204.     /* That's it! */
  205.     *intp = value;
  206.     return (bufp);
  207. }
  208. /*
  209.  * asn_build_int - builds an ASN object containing an integer.
  210.  *  On entry, datalength is input as the number of valid bytes following
  211.  *   "data".  On exit, it is returned as the number of valid bytes
  212.  *   following the end of this object.
  213.  *
  214.  *  Returns a pointer to the first byte past the end
  215.  *   of this object (i.e. the start of the next object).
  216.  *  Returns NULL on any error.
  217.  */
  218. u_char *
  219. asn_build_int(u_char * data, int *datalength,
  220.     u_char type, int *intp, int intsize)
  221.   /*     u_char *data;         IN - pointer to start of output buffer */
  222.   /*     int    *datalength;   IN/OUT - # of valid bytes left in buffer */
  223.   /*     u_char  type;         IN - asn type of object */
  224.   /*     int   *intp;          IN - pointer to start of integer */
  225.   /*     int    intsize;       IN - size of *intp */
  226. {
  227.     /*
  228.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  229.      */
  230.     int integer;
  231.     u_int mask;
  232.     if (intsize != sizeof(int)) {
  233. snmp_set_api_error(SNMPERR_ASN_ENCODE);
  234. return (NULL);
  235.     }
  236.     integer = *intp;
  237.     /*
  238.      * Truncate "unnecessary" bytes off of the most significant end of this
  239.      * 2's complement integer.  There should be no sequence of 9
  240.      * consecutive 1's or 0's at the most significant end of the
  241.      * integer.
  242.      */
  243.     mask = (u_int) 0x1FF << ((8 * (sizeof(int) - 1)) - 1);
  244.     /* mask is 0xFF800000 on a big-endian machine */
  245.     while ((((integer & mask) == 0) || ((integer & mask) == mask))
  246. && intsize > 1) {
  247. intsize--;
  248. integer <<= 8;
  249.     }
  250.     data = asn_build_header_with_truth(data, datalength, type, intsize, 1);
  251.     if (data == NULL)
  252. return (NULL);
  253.     /* Enough room for what we just encoded? */
  254.     if (*datalength < intsize) {
  255. snmp_set_api_error(SNMPERR_ASN_ENCODE);
  256. return (NULL);
  257.     }
  258.     /* Insert it */
  259.     *datalength -= intsize;
  260.     mask = (u_int) 0xFF << (8 * (sizeof(int) - 1));
  261.     /* mask is 0xFF000000 on a big-endian machine */
  262.     while (intsize--) {
  263. *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(int) - 1)));
  264. integer <<= 8;
  265.     }
  266.     return (data);
  267. }
  268. /*
  269.  * asn_build_unsigned_int - builds an ASN object containing an integer.
  270.  *  On entry, datalength is input as the number of valid bytes following
  271.  *   "data".  On exit, it is returned as the number of valid bytes
  272.  *   following the end of this object.
  273.  *
  274.  *  Returns a pointer to the first byte past the end
  275.  *   of this object (i.e. the start of the next object).
  276.  *  Returns NULL on any error.
  277.  */
  278. u_char *
  279. asn_build_unsigned_int(u_char * data, int *datalength,
  280.     u_char type, u_int * intp, int intsize)
  281.   /*     u_char *data;         IN     - pointer to start of output buffer */
  282.   /*     int    *datalength;   IN/OUT - # of valid bytes left in buffer */
  283.   /*     u_char  type;         IN     - asn type of object */
  284.   /*     u_int  *intp;         IN     - pointer to start of integer */
  285.   /*     int     intsize;      IN     - size of *intp */
  286. {
  287.     /*
  288.      * ASN.1 integer ::= 0x02 asnlength byte {byte}*
  289.      */
  290.     u_int integer;
  291.     u_int mask;
  292.     int add_null_byte = 0;
  293.     if (intsize != sizeof(int)) {
  294. snmp_set_api_error(SNMPERR_ASN_ENCODE);
  295. return (NULL);
  296.     }
  297.     integer = *intp;
  298.     mask = (u_int) 0xFF << (8 * (sizeof(int) - 1));
  299.     /* mask is 0xFF000000 on a big-endian machine */
  300.     if ((u_char) ((integer & mask) >> (8 * (sizeof(int) - 1))) & 0x80) {
  301. /* if MSB is set */
  302. add_null_byte = 1;
  303. intsize++;
  304.     }
  305.     /*
  306.      * Truncate "unnecessary" bytes off of the most significant end of
  307.      * this 2's complement integer. 
  308.      * There should be no sequence of 9 consecutive 1's or 0's at the
  309.      * most significant end of the integer.
  310.      */
  311.     mask = (u_int) 0x1FF << ((8 * (sizeof(int) - 1)) - 1);
  312.     /* mask is 0xFF800000 on a big-endian machine */
  313.     while ((((integer & mask) == 0)
  314.     || ((integer & mask) == mask)) && intsize > 1) {
  315. intsize--;
  316. integer <<= 8;
  317.     }
  318.     data = asn_build_header_with_truth(data, datalength, type, intsize, 1);
  319.     if (data == NULL)
  320. return (NULL);
  321.     if (*datalength < intsize) {
  322. snmp_set_api_error(SNMPERR_ASN_ENCODE);
  323. return (NULL);
  324.     }
  325.     *datalength -= intsize;
  326.     if (add_null_byte == 1) {
  327. *data++ = '';
  328. intsize--;
  329.     }
  330.     mask = (u_int) 0xFF << (8 * (sizeof(int) - 1));
  331.     /* mask is 0xFF000000 on a big-endian machine */
  332.     while (intsize--) {
  333. *data++ = (u_char) ((integer & mask) >> (8 * (sizeof(int) - 1)));
  334. integer <<= 8;
  335.     }
  336.     return (data);
  337. }
  338. /*
  339.  * asn_parse_string - pulls an octet string out of an ASN octet string type.
  340.  *  On entry, datalength is input as the number of valid bytes following
  341.  *   "data".  On exit, it is returned as the number of valid bytes
  342.  *   following the beginning of the next object.
  343.  *
  344.  *  "string" is filled with the octet string.
  345.  *
  346.  *  Returns a pointer to the first byte past the end
  347.  *   of this object (i.e. the start of the next object).
  348.  *  Returns NULL on any error.
  349.  */
  350. u_char *
  351. asn_parse_string(u_char * data, int *datalength,
  352.     u_char * type, u_char * string, int *strlength)
  353.   /*    u_char *data;       IN - pointer to start of object */
  354.   /*    int    *datalength; IN/OUT - # of valid bytes left in buffer */
  355.   /*    u_char *type;       OUT - asn type of object */
  356.   /*    u_char *string;     IN/OUT - pointer to start of output buffer */
  357.   /*    int    *strlength;  IN/OUT - size of output buffer */
  358. {
  359.     /*
  360.      * ASN.1 octet string ::= primstring | cmpdstring
  361.      * primstring ::= 0x04 asnlength byte {byte}*
  362.      * cmpdstring ::= 0x24 asnlength string {string}*
  363.      */
  364.     u_char *bufp = data;
  365.     u_int asn_length;
  366.     *type = *bufp++;
  367.     bufp = asn_parse_length(bufp, &asn_length);
  368.     if (bufp == NULL)
  369. return (NULL);
  370.     if (asn_length + (bufp - data) > *datalength) {
  371. snmp_set_api_error(SNMPERR_ASN_DECODE);
  372. return (NULL);
  373.     }
  374.     if (asn_length > *strlength) {
  375. snmp_set_api_error(SNMPERR_ASN_DECODE);
  376. return (NULL);
  377.     }
  378.     xmemcpy((char *) string, (char *) bufp, (int) asn_length);
  379.     *strlength = (int) asn_length;
  380.     *datalength -= (int) asn_length + (bufp - data);
  381.     return (bufp + asn_length);
  382. }
  383. /*
  384.  * asn_build_string - Builds an ASN octet string object containing the input
  385.  *   string.  On entry, datalength is input as the number of valid bytes 
  386.  *   following "data".  On exit, it is returned as the number of valid bytes
  387.  *   following the beginning of the next object.
  388.  *
  389.  *  Returns a pointer to the first byte past the end
  390.  *   of this object (i.e. the start of the next object).
  391.  *  Returns NULL on any error.
  392.  */
  393. u_char *
  394. asn_build_string(u_char * data, int *datalength,
  395.     u_char type, u_char * string, int strlength)
  396.   /*    u_char *data;       IN - pointer to start of object */
  397.   /*    int    *datalength; IN/OUT - # of valid bytes left in buf */
  398.   /*    u_char  type;       IN - ASN type of string */
  399.   /*    u_char *string;     IN - pointer to start of input buffer */
  400.   /*    int     strlength;  IN - size of input buffer */
  401. {
  402.     /*
  403.      * ASN.1 octet string ::= primstring | cmpdstring
  404.      * primstring ::= 0x04 asnlength byte {byte}*
  405.      * cmpdstring ::= 0x24 asnlength string {string}*
  406.      * This code will never send a compound string.
  407.      */
  408.     data = asn_build_header_with_truth(data, datalength, type, strlength, 1);
  409.     if (data == NULL)
  410. return (NULL);
  411.     if (*datalength < strlength) {
  412. snmp_set_api_error(SNMPERR_ASN_DECODE);
  413. return (NULL);
  414.     }
  415.     xmemcpy((char *) data, (char *) string, strlength);
  416.     *datalength -= strlength;
  417.     return (data + strlength);
  418. }
  419. /*
  420.  * asn_parse_header - interprets the ID and length of the current object.
  421.  *  On entry, datalength is input as the number of valid bytes following
  422.  *   "data".  On exit, it is returned as the number of valid bytes
  423.  *   in this object following the id and length.
  424.  *
  425.  *  Returns a pointer to the first byte of the contents of this object.
  426.  *  Returns NULL on any error.
  427.  */
  428. u_char *
  429. asn_parse_header(u_char * data, int *datalength, u_char * type)
  430.   /*    u_char  *data;       IN - pointer to start of object */
  431.   /*    int     *datalength; IN/OUT - # of valid bytes left in buffer */
  432.   /*    u_char  *type;       OUT - ASN type of object */
  433. {
  434.     u_char *bufp = data;
  435.     int header_len;
  436.     u_int asn_length;
  437.     /* this only works on data types < 30, i.e. no extension octets */
  438.     if (IS_EXTENSION_ID(*bufp)) {
  439. snmp_set_api_error(SNMPERR_ASN_DECODE);
  440. return (NULL);
  441.     }
  442.     *type = *bufp;
  443.     bufp = asn_parse_length(bufp + 1, &asn_length);
  444.     if (bufp == NULL)
  445. return (NULL);
  446.     header_len = bufp - data;
  447.     if (header_len + asn_length > *datalength) {
  448. snmp_set_api_error(SNMPERR_ASN_DECODE);
  449. return (NULL);
  450.     }
  451.     *datalength = (int) asn_length;
  452.     return (bufp);
  453. }
  454. /*
  455.  * asn_build_header - builds an ASN header for an object with the ID and
  456.  * length specified.
  457.  *  On entry, datalength is input as the number of valid bytes following
  458.  *   "data".  On exit, it is returned as the number of valid bytes
  459.  *   in this object following the id and length.
  460.  *
  461.  *  This only works on data types < 30, i.e. no extension octets.
  462.  *  The maximum length is 0xFFFF;
  463.  *
  464.  *  Returns a pointer to the first byte of the contents of this object.
  465.  *  Returns NULL on any error.
  466.  */
  467. u_char *
  468. asn_build_header_with_truth(u_char * data, int *datalength,
  469.     u_char type, int length, int truth)
  470.   /*    u_char *data;       IN - pointer to start of object */
  471.   /*    int    *datalength; IN/OUT - # of valid bytes left in buffer */
  472.   /*    u_char  type;       IN - ASN type of object */
  473.   /*    int     length;     IN - length of object */
  474.   /*    int     truth;      IN - Whether length is truth */
  475. {
  476.     if (*datalength < 1) {
  477. snmp_set_api_error(SNMPERR_ASN_ENCODE);
  478. return (NULL);
  479.     }
  480.     *data++ = type;
  481.     (*datalength)--;
  482.     return (asn_build_length(data, datalength, length, truth));
  483. }
  484. #if 0
  485. /*
  486.  * asn_build_sequence - builds an ASN header for a sequence with the ID and
  487.  * length specified.
  488.  *  On entry, datalength is input as the number of valid bytes following
  489.  *   "data".  On exit, it is returned as the number of valid bytes
  490.  *   in this object following the id and length.
  491.  *
  492.  *  This only works on data types < 30, i.e. no extension octets.
  493.  *  The maximum length is 0xFFFF;
  494.  *
  495.  *  Returns a pointer to the first byte of the contents of this object.
  496.  *  Returns NULL on any error.
  497.  */
  498. u_char *
  499. asn_build_sequence(u_char * data, int *datalength,
  500.     u_char type, int length)
  501.   /*    u_char *data;       IN - pointer to start of object */
  502.   /*    int    *datalength; IN/OUT - # of valid bytes left in buffer */
  503.   /*    u_char  type;       IN - ASN type of object */
  504.   /*    int     length;     IN - length of object */
  505. {
  506.     *datalength -= 4;
  507.     if (*datalength < 0) {
  508. *datalength += 4; /* fix up before punting */
  509. snmp_set_api_error(SNMPERR_ASN_ENCODE);
  510. return (NULL);
  511.     }
  512.     *data++ = type;
  513.     *data++ = (u_char) (0x02 | ASN_LONG_LEN);
  514.     *data++ = (u_char) ((length >> 8) & 0xFF);
  515.     *data++ = (u_char) (length & 0xFF);
  516.     return (data);
  517. }
  518. #endif
  519. /*
  520.  * asn_parse_length - interprets the length of the current object.
  521.  *  On exit, length contains the value of this length field.
  522.  *
  523.  *  Returns a pointer to the first byte after this length
  524.  *  field (aka: the start of the data field).
  525.  *  Returns NULL on any error.
  526.  */
  527. u_char *
  528. asn_parse_length(u_char * data, u_int * length)
  529.   /*    u_char  *data;   IN - pointer to start of length field */
  530.   /*    u_int  *length; OUT - value of length field */
  531. {
  532.     u_char lengthbyte = *data;
  533.     if (lengthbyte & ASN_LONG_LEN) {
  534. lengthbyte &= ~ASN_LONG_LEN; /* turn MSb off */
  535. if (lengthbyte == 0) {
  536.     snmp_set_api_error(SNMPERR_ASN_DECODE);
  537.     return (NULL);
  538. }
  539. if (lengthbyte > sizeof(int)) {
  540.     snmp_set_api_error(SNMPERR_ASN_DECODE);
  541.     return (NULL);
  542. }
  543. *length = (u_int) 0;
  544. xmemcpy((char *) (length), (char *) data + 1, (int) lengthbyte);
  545. *length = ntohl(*length);
  546. *length >>= (8 * ((sizeof *length) - lengthbyte));
  547. return (data + lengthbyte + 1);
  548.     }
  549.     /* short asnlength */
  550.     *length = (int) lengthbyte;
  551.     return (data + 1);
  552. }
  553. u_char *
  554. asn_build_length(u_char * data, int *datalength,
  555.     int length, int truth)
  556.   /*   u_char *data;       IN - pointer to start of object */
  557.   /*   int    *datalength; IN/OUT - # of valid bytes left in buf */
  558.   /*   int     length;     IN - length of object */
  559.   /*   int     truth;      IN - If 1, this is the true len. */
  560. {
  561.     u_char *start_data = data;
  562.     if (truth) {
  563. /* no indefinite lengths sent */
  564. if (length < 0x80) {
  565.     if (*datalength < 1) {
  566. snmp_set_api_error(SNMPERR_ASN_ENCODE);
  567. return (NULL);
  568.     }
  569.     *data++ = (u_char) length;
  570. } else if (length <= 0xFF) {
  571.     if (*datalength < 2) {
  572. snmp_set_api_error(SNMPERR_ASN_ENCODE);
  573. return (NULL);
  574.     }
  575.     *data++ = (u_char) (0x01 | ASN_LONG_LEN);
  576.     *data++ = (u_char) length;
  577. } else { /* 0xFF < length <= 0xFFFF */
  578.     if (*datalength < 3) {
  579. snmp_set_api_error(SNMPERR_ASN_ENCODE);
  580. return (NULL);
  581.     }
  582.     *data++ = (u_char) (0x02 | ASN_LONG_LEN);
  583.     *data++ = (u_char) ((length >> 8) & 0xFF);
  584.     *data++ = (u_char) (length & 0xFF);
  585. }
  586.     } else {
  587. /* Don't know if this is the true length.  Make sure it's large
  588.  * enough for later.
  589.  */
  590. if (*datalength < 3) {
  591.     snmp_set_api_error(SNMPERR_ASN_ENCODE);
  592.     return (NULL);
  593. }
  594. *data++ = (u_char) (0x02 | ASN_LONG_LEN);
  595. *data++ = (u_char) ((length >> 8) & 0xFF);
  596. *data++ = (u_char) (length & 0xFF);
  597.     }
  598.     *datalength -= (data - start_data);
  599.     return (data);
  600. }
  601. /*
  602.  * asn_parse_objid - pulls an object indentifier out of an ASN object
  603.  * identifier type.
  604.  *  On entry, datalength is input as the number of valid bytes following
  605.  *   "data".  On exit, it is returned as the number of valid bytes
  606.  *   following the beginning of the next object.
  607.  *
  608.  *  "objid" is filled with the object identifier.
  609.  *
  610.  *  Returns a pointer to the first byte past the end
  611.  *   of this object (i.e. the start of the next object).
  612.  *  Returns NULL on any error.
  613.  */
  614. u_char *
  615. asn_parse_objid(u_char * data, int *datalength,
  616.     u_char * type, oid * objid, int *objidlength)
  617.   /*    u_char  *data;        IN - pointer to start of object */
  618.   /*    int     *datalength;  IN/OUT - # of valid bytes left in buf */
  619.   /*    u_char  *type;        OUT - ASN type of object */
  620.   /*    oid     *objid;       IN/OUT - pointer to start of output buffer */
  621.   /*    int     *objidlength; IN/OUT - number of sub-id's in objid */
  622. {
  623.     /*
  624.      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
  625.      * subidentifier ::= {leadingbyte}* lastbyte
  626.      * leadingbyte ::= 1 7bitvalue
  627.      * lastbyte ::= 0 7bitvalue
  628.      */
  629.     u_char *bufp = data;
  630.     oid *oidp = objid + 1;
  631.     u_int subidentifier;
  632.     int length;
  633.     u_int asn_length;
  634.     *type = *bufp++;
  635.     bufp = asn_parse_length(bufp, &asn_length);
  636.     if (bufp == NULL)
  637. return (NULL);
  638.     if (asn_length + (bufp - data) > *datalength) {
  639. snmp_set_api_error(SNMPERR_ASN_DECODE);
  640. return (NULL);
  641.     }
  642.     *datalength -= (int) asn_length + (bufp - data);
  643.     /* Handle invalid object identifier encodings of the form 06 00 robustly */
  644.     if (asn_length == 0)
  645. objid[0] = objid[1] = 0;
  646.     length = asn_length;
  647.     (*objidlength)--; /* account for expansion of first byte */
  648.     while (length > 0 && (*objidlength)-- > 0) {
  649. subidentifier = 0;
  650. do { /* shift and add in low order 7 bits */
  651.     subidentifier = (subidentifier << 7)
  652. + (*(u_char *) bufp & ~ASN_BIT8);
  653.     length--;
  654. } while (*(u_char *) bufp++ & ASN_BIT8);
  655. /* while last byte has high bit clear */
  656. if (subidentifier > (u_int) MAX_SUBID) {
  657.     snmp_set_api_error(SNMPERR_ASN_DECODE);
  658.     return (NULL);
  659. }
  660. *oidp++ = (oid) subidentifier;
  661.     }
  662.     /*
  663.      * The first two subidentifiers are encoded into the first component
  664.      * with the value (X * 40) + Y, where:
  665.      *  X is the value of the first subidentifier.
  666.      *  Y is the value of the second subidentifier.
  667.      */
  668.     subidentifier = (u_int) objid[1];
  669.     if (subidentifier == 0x2B) {
  670. objid[0] = 1;
  671. objid[1] = 3;
  672.     } else {
  673. objid[1] = (u_char) (subidentifier % 40);
  674. objid[0] = (u_char) ((subidentifier - objid[1]) / 40);
  675.     }
  676.     *objidlength = (int) (oidp - objid);
  677.     return (bufp);
  678. }
  679. /*
  680.  * asn_build_objid - Builds an ASN object identifier object containing the
  681.  * input string.
  682.  *  On entry, datalength is input as the number of valid bytes following
  683.  *   "data".  On exit, it is returned as the number of valid bytes
  684.  *   following the beginning of the next object.
  685.  *
  686.  *  Returns a pointer to the first byte past the end
  687.  *   of this object (i.e. the start of the next object).
  688.  *  Returns NULL on any error.
  689.  */
  690. u_char *
  691. asn_build_objid(u_char * data, int *datalength,
  692.     u_char type, oid * objid, int objidlength)
  693.   /*    u_char *data;         IN - pointer to start of object */
  694.   /*    int    *datalength;   IN/OUT - # of valid bytes left in buf */
  695.   /*    u_char  type;         IN - ASN type of object */
  696.   /*    oid    *objid;        IN - pointer to start of input buffer */
  697.   /*    int     objidlength;  IN - number of sub-id's in objid */
  698. {
  699.     /*
  700.      * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
  701.      * subidentifier ::= {leadingbyte}* lastbyte
  702.      * leadingbyte ::= 1 7bitvalue
  703.      * lastbyte ::= 0 7bitvalue
  704.      */
  705.     u_char buf[MAX_OID_LEN];
  706.     u_char *bp = buf;
  707.     oid *op = objid;
  708.     int asnlength;
  709.     u_int subid, mask, testmask;
  710.     int bits, testbits;
  711.     if (objidlength < 2) {
  712. *bp++ = 0;
  713. objidlength = 0;
  714.     } else {
  715. *bp++ = op[1] + (op[0] * 40);
  716. objidlength -= 2;
  717. op += 2;
  718.     }
  719.     while (objidlength-- > 0) {
  720. subid = *op++;
  721. if (subid < 127) { /* off by one? */
  722.     *bp++ = subid;
  723. } else {
  724.     mask = 0x7F; /* handle subid == 0 case */
  725.     bits = 0;
  726.     /* testmask *MUST* !!!! be of an unsigned type */
  727.     for (testmask = 0x7F, testbits = 0; testmask != 0;
  728. testmask <<= 7, testbits += 7) {
  729. if (subid & testmask) { /* if any bits set */
  730.     mask = testmask;
  731.     bits = testbits;
  732. }
  733.     }
  734.     /* mask can't be zero here */
  735.     for (; mask != 0x7F; mask >>= 7, bits -= 7) {
  736. /* fix a mask that got truncated above */
  737. if (mask == 0x1E00000)
  738.     mask = 0xFE00000;
  739. *bp++ = (u_char) (((subid & mask) >> bits) | ASN_BIT8);
  740.     }
  741.     *bp++ = (u_char) (subid & mask);
  742. }
  743.     }
  744.     asnlength = bp - buf;
  745.     data = asn_build_header_with_truth(data, datalength, type, asnlength, 1);
  746.     if (data == NULL)
  747. return (NULL);
  748.     if (*datalength < asnlength) {
  749. snmp_set_api_error(SNMPERR_ASN_DECODE);
  750. return (NULL);
  751.     }
  752.     xmemcpy((char *) data, (char *) buf, asnlength);
  753.     *datalength -= asnlength;
  754.     return (data + asnlength);
  755. }
  756. #if 0
  757. /*
  758.  * asn_parse_null - Interprets an ASN null type.
  759.  *  On entry, datalength is input as the number of valid bytes following
  760.  *   "data".  On exit, it is returned as the number of valid bytes
  761.  *   following the beginning of the next object.
  762.  *
  763.  *  Returns a pointer to the first byte past the end
  764.  *   of this object (i.e. the start of the next object).
  765.  *  Returns NULL on any error.
  766.  */
  767. u_char *
  768. asn_parse_null(u_char * data, int *datalength, u_char * type)
  769.   /*    u_char  *data;       IN - pointer to start of object */
  770.   /*    int     *datalength; IN/OUT - # of valid bytes left in buf */
  771.   /*    u_char  *type;       OUT - ASN type of object */
  772. {
  773.     /*
  774.      * ASN.1 null ::= 0x05 0x00
  775.      */
  776.     u_char *bufp = data;
  777.     u_int asn_length;
  778.     *type = *bufp++;
  779.     bufp = asn_parse_length(bufp, &asn_length);
  780.     if (bufp == NULL)
  781. return (NULL);
  782.     if (asn_length != 0) {
  783. snmp_set_api_error(SNMPERR_ASN_DECODE);
  784. return (NULL);
  785.     }
  786.     *datalength -= (bufp - data);
  787.     return (bufp + asn_length);
  788. }
  789. #endif
  790. /*
  791.  * asn_build_null - Builds an ASN null object.
  792.  *  On entry, datalength is input as the number of valid bytes following
  793.  *   "data".  On exit, it is returned as the number of valid bytes
  794.  *   following the beginning of the next object.
  795.  *
  796.  *  Returns a pointer to the first byte past the end
  797.  *   of this object (i.e. the start of the next object).
  798.  *  Returns NULL on any error.
  799.  */
  800. u_char *
  801. asn_build_null(u_char * data, int *datalength, u_char type)
  802.   /*    u_char  *data;       IN - pointer to start of object */
  803.   /*    int     *datalength; IN/OUT - # of valid bytes left in buf */
  804.   /*    u_char   type;       IN - ASN type of object */
  805. {
  806.     /*
  807.      * ASN.1 null ::= 0x05 0x00
  808.      */
  809.     return (asn_build_header_with_truth(data, datalength, type, 0, 1));
  810. }
  811. #if 0
  812. /*
  813.  * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring type.
  814.  *  On entry, datalength is input as the number of valid bytes following
  815.  *   "data".  On exit, it is returned as the number of valid bytes
  816.  *   following the beginning of the next object.
  817.  *
  818.  *  "string" is filled with the bit string.
  819.  *
  820.  *  Returns a pointer to the first byte past the end
  821.  *   of this object (i.e. the start of the next object).
  822.  *  Returns NULL on any error.
  823.  */
  824. u_char *
  825. asn_parse_bitstring(u_char * data, int *datalength,
  826.     u_char * type, u_char * string, int *strlength)
  827.   /*   u_char  *data;        IN - pointer to start of object */
  828.   /*   int     *datalength;  IN/OUT - # of valid bytes left in buf */
  829.   /*   u_char  *type;        OUT - asn type of object */
  830.   /*   u_char  *string;      IN/OUT - pointer to start of output buf */
  831.   /*   int     *strlength;   IN/OUT - size of output buffer */
  832. {
  833.     /*
  834.      * bitstring ::= 0x03 asnlength unused {byte}*
  835.      */
  836.     u_char *bufp = data;
  837.     u_int asn_length;
  838.     *type = *bufp++;
  839.     bufp = asn_parse_length(bufp, &asn_length);
  840.     if (bufp == NULL)
  841. return (NULL);
  842.     if (asn_length + (bufp - data) > *datalength) {
  843. snmp_set_api_error(SNMPERR_ASN_DECODE);
  844. return (NULL);
  845.     }
  846.     if (asn_length > *strlength) {
  847. snmp_set_api_error(SNMPERR_ASN_DECODE);
  848. return (NULL);
  849.     }
  850.     if (asn_length < 1) {
  851. snmp_set_api_error(SNMPERR_ASN_DECODE);
  852. return (NULL);
  853.     }
  854.     if ((int) (*(char *) bufp) < 0 || (int) (*bufp) > 7) {
  855. snmp_set_api_error(SNMPERR_ASN_DECODE);
  856. return (NULL);
  857.     }
  858.     xmemcpy((char *) string, (char *) bufp, (int) asn_length);
  859.     *strlength = (int) asn_length;
  860.     *datalength -= (int) asn_length + (bufp - data);
  861.     return (bufp + asn_length);
  862. }
  863. /*
  864.  * asn_build_bitstring - Builds an ASN bit string object containing the
  865.  * input string.
  866.  *  On entry, datalength is input as the number of valid bytes following
  867.  *   "data".  On exit, it is returned as the number of valid bytes
  868.  *   following the beginning of the next object.
  869.  *
  870.  *  Returns a pointer to the first byte past the end
  871.  *   of this object (i.e. the start of the next object).
  872.  *  Returns NULL on any error.
  873.  */
  874. u_char *
  875. asn_build_bitstring(u_char * data, int *datalength,
  876.     u_char type, u_char * string, int strlength)
  877.   /*   u_char  *data;       IN - pointer to start of object */
  878.   /*   int     *datalength; IN/OUT - # of valid bytes left in buf */
  879.   /*   u_char   type;       IN - ASN type of string */
  880.   /*   u_char  *string;     IN - pointer to start of input buffer */
  881.   /*   int      strlength;  IN - size of input buffer */
  882. {
  883.     /*
  884.      * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
  885.      */
  886.     if ((strlength < 1) || ((*(char *) string) < 0) || ((*string) > 7)) {
  887. snmp_set_api_error(SNMPERR_ASN_ENCODE);
  888. return (NULL);
  889.     }
  890.     data = asn_build_header_with_truth(data, datalength, type, strlength, 1);
  891.     if (data == NULL)
  892. return (NULL);
  893.     if (*datalength < strlength) {
  894. snmp_set_api_error(SNMPERR_ASN_ENCODE);
  895. return (NULL);
  896.     }
  897.     xmemcpy((char *) data, (char *) string, strlength);
  898.     *datalength -= strlength;
  899.     return (data + strlength);
  900. }
  901. #endif
  902. /*
  903.  * To do: Write an asn_parse_exception function to go with the new 
  904.  * asn_build_exception function below so that the exceptional values can
  905.  * be handled in input packets aswell as output ones.
  906.  */
  907. /*
  908.  * asn_build_exception - Builds an ASN exception object.
  909.  *  On entry, datalength is input as the number of valid bytes following
  910.  *   "data".  On exit, it is returned as the number of valid bytes
  911.  *   following the beginning of the next object.
  912.  *
  913.  *  Returns a pointer to the first byte past the end
  914.  *   of this object (i.e. the start of the next object).
  915.  *  Returns NULL on any error.
  916.  *
  917.  * ASN.1 variable exception ::= 0x8i 0x00, where 'i' is one of these 
  918.  *                                         exception identifiers:
  919.  *                                           0 -- noSuchObject
  920.  *                                           1 -- noSuchInstance
  921.  *                                           2 -- endOfMibView
  922.  */
  923. u_char *
  924. asn_build_exception(u_char * data, int *datalength, u_char type)
  925.   /*    u_char  *data;       IN - pointer to start of object */
  926.   /*    int     *datalength; IN/OUT - # of valid bytes left in buf */
  927.   /*    u_char   type;       IN - ASN type of object */
  928. {
  929.     return (asn_build_header_with_truth(data, datalength, type, 0, 1));
  930. }