asn1.cpp

来自「HP公司的SNMP++的Win32版本源码」· C++ 代码 · 共 1,758 行 · 第 1/4 页

CPP
1,758
字号
/*===================================================================
   
  Copyright (c) 1999
  Hewlett-Packard Company

  ATTENTION: USE OF THIS SOFTWARE IS SUBJECT TO THE FOLLOWING TERMS.
  Permission to use, copy, modify, distribute and/or sell this software 
  and/or its documentation is hereby granted without fee. User agrees 
  to display the above copyright notice and this license notice in all 
  copies of the software and any documentation of the software. User 
  agrees to assume all liability for the use of the software; Hewlett-Packard 
  makes no representations about the suitability of this software for any 
  purpose. It is provided "AS-IS without warranty of any kind,either express 
  or implied. User hereby grants a royalty-free license to any and all 
  derivatives based upon this software code base. 



  A S N 1. C P P

  ASN encoder / decoder implementation

  VERSION 2.8

  DESIGN:
  Peter E. Mellquist

  AUTHOR:
  Peter E Mellquist

  
  LANGUAGE:
  ANSI C++

  OPERATING SYSTEM(S):
  MS-Windows Win32
  BSD UNIX

=====================================================================*/

#ifdef unix 
#include /**/ <sys/types.h>
#include /**/ <netinet/in.h>
#include /**/ <stdlib.h>
#endif

#include "asn1.h"
#include "snmp_pp.h"

#ifdef WIN32
#include <winsock.h>
#endif

#ifndef NULL
#define NULL	0
#endif

#define LENMASK 0x0ff

/*
 * asn_parse_int - pulls a long out of an ASN int type.
 *  On entry, datalength is input as the number of valid bytes following
 *   "data".  On exit, it is returned as the number of valid bytes
 *   following the end of this object.
 *
 *  Returns a pointer to the first byte past the end
 *   of this object (i.e. the start of the next object).
 *  Returns NULL on any error.
 */
unsigned char * asn_parse_int( unsigned char *data, 
			                   int *datalength, 
			                   unsigned char *type, 
			                   long int *intp, 
			                   int intsize)
{
/*
 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
 */
    unsigned char *bufp = data;
    unsigned long	    asn_length;
    long   value = 0;

    if (intsize != sizeof (long)){
	ASNERROR("not long");
	return NULL;
    }
    *type = *bufp++;
    bufp = asn_parse_length(bufp, &asn_length);
    if (bufp == NULL){
	ASNERROR("bad length");
	return NULL;
    }
    if ((int)(asn_length + (bufp - data)) > *datalength){
	ASNERROR("overflow of message");
	return NULL;
    }
    if ((int)asn_length > intsize){
	ASNERROR("I don't support such large integers");
	return NULL;
    }
    *datalength -= (int)asn_length + (bufp - data);
    if (*bufp & 0x80)
	value = -1; /* integer is negative */
    while(asn_length--)
	value = (value << 8) | *bufp++;
    *intp = value;
    return bufp;
};


/*
 * asn_parse_unsigned_int - pulls an unsigned long out of an ASN int type.
 *  On entry, datalength is input as the number of valid bytes following
 *   "data".  On exit, it is returned as the number of valid bytes
 *   following the end of this object.
 *
 *  Returns a pointer to the first byte past the end
 *   of this object (i.e. the start of the next object).
 *  Returns NULL on any error.
 */
unsigned char * asn_parse_unsigned_int( unsigned char *data,	
                                        int *datalength,
                                        unsigned char *type,
                                        unsigned long *intp,
                                        int	intsize)
{
/*
 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
 */
    unsigned char *bufp = data;
    unsigned long	    asn_length;
    unsigned long value = 0;

	// check the size of the object being requested
    if (intsize != sizeof (long)){
	   ASNERROR("not long");
	   return NULL;
    }

	// get the type
    *type = *bufp++;

	// pick up the len
    bufp = asn_parse_length(bufp, &asn_length);
    if (bufp == NULL){
	   ASNERROR("bad length");
	   return NULL;
    }

	// check the len for message overflow
    if ((int)(asn_length + (bufp - data)) > *datalength){
	   ASNERROR("overflow of message");
	   return NULL;
    }

	// check for legal uint size
	if (( (int)asn_length > 5) || (((int)asn_length > 4) && (*bufp != 0x00))) {
	   ASNERROR("I don't support such large integers");
	   return NULL;
    }

	// check for leading  0 octet
	if (*bufp == 0x00) {
		bufp++;
		asn_length--;
	}

	// fix the returned data length value
    *datalength -= (int)asn_length + (bufp - data);

	// calculate the value
    for (long i=0;i<(long)asn_length;i++)
	   value = (value << 8) + (unsigned long) *bufp++;

	// assign return value
    *intp = value;

	// return the bumped pointer
    return bufp;
};


/*
 * asn_build_int - builds an ASN object containing an integer.
 *  On entry, datalength is input as the number of valid bytes following
 *   "data".  On exit, it is returned as the number of valid bytes
 *   following the end of this object.
 *
 *  Returns a pointer to the first byte past the end
 *   of this object (i.e. the start of the next object).
 *  Returns NULL on any error.
 */
unsigned char * asn_build_int( unsigned char *data,
                               int *datalength,
                               unsigned char type,
                               long *intp,
                               int intsize)
{
/*
 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
 */

    long integer;
    unsigned long mask;

    if (intsize != sizeof (long))
	return NULL;
    integer = *intp;
    /*
     * Truncate "unnecessary" bytes off of the most significant end of this
     * 2's complement integer.  There should be no sequence of 9
     * consecutive 1's or 0's at the most significant end of the
     * integer.
     */
    mask = 0x1FF << ((8 * (sizeof(long) - 1)) - 1);
    /* mask is 0xFF800000 on a big-endian machine */
    while((((integer & mask) == 0) || ((integer & mask) == mask))
	  && intsize > 1){
	intsize--;
	integer <<= 8;
    }
    data = asn_build_header(data, datalength, type, intsize);
    if (data == NULL)
	return NULL;
    if (*datalength < intsize)
	return NULL;
    *datalength -= intsize;
    mask = 0xFF << (8 * (sizeof(long) - 1));
    /* mask is 0xFF000000 on a big-endian machine */
    while(intsize--){
	*data++ = (unsigned char)((integer & mask) >> (8 * (sizeof(long) - 1)));
	integer <<= 8;
    }
    return data;
};


/*
 * asn_build_unsigned_int - builds an ASN object containing an integer.
 *  On entry, datalength is input as the number of valid bytes following
 *   "data".  On exit, it is returned as the number of valid bytes
 *   following the end of this object.
 *
 *  Returns a pointer to the first byte past the end
 *   of this object (i.e. the start of the next object).
 *  Returns NULL on any error.
 */
unsigned char * asn_build_unsigned_int( unsigned char *data,   // modified data
                                        int *datalength,       // returned buffer length 
                                        unsigned char type,	   // SMI type
                                        unsigned long *intp,   // Uint to encode
                                        int intsize)           // size of uint to encode
{
/*
 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
 */

    unsigned long u_integer;
    int add_null_byte = 0;
	long u_integer_len;
	long x;

	// check uint size
    if (intsize != sizeof (long))
	   return NULL;


	// local var point to var passed in
    u_integer = *intp;

	// figure out the len 
	if ((( u_integer >> 24) & LENMASK) != 0)
	    u_integer_len = 4;
	else if ((( u_integer >> 16) & LENMASK) !=0)
		    u_integer_len = 3;
	     else if ((( u_integer >> 8) & LENMASK) !=0)
			     u_integer_len = 2;
		      else
				 u_integer_len =1;

	// check for 5 byte len where first byte will be
    // a null
	if ((( u_integer >> (8 * (u_integer_len -1))) & 0x080) !=0)	{
		u_integer_len++;
		intsize++;
	}

	// build up the header
	data = asn_build_header( data,                 // data buffer to be modified
							 datalength,           // length of data buffer
							 type,                 // SMI type to enode
							 (int)u_integer_len);  // length of BER encoded item

	// special case, add a null byte for len of 5
	if ( u_integer_len ==5) {
	  *data++ = (unsigned char) 0;
	  for (x=1;x<u_integer_len;x++)
		  *data++= (unsigned char) ( u_integer >> (8 * ((u_integer_len-1)-x)& LENMASK));
	}
	else
    {
	   for (x=0;x<u_integer_len;x++)
		  *data++= (unsigned char) ( u_integer >> (8 * ((u_integer_len-1)-x)& LENMASK));
    }
    
	return data;
};


/*
 * asn_parse_string - pulls an octet string out of an ASN octet string type.
 *  On entry, datalength is input as the number of valid bytes following
 *   "data".  On exit, it is returned as the number of valid bytes
 *   following the beginning of the next object.
 *
 *  "string" is filled with the octet string.
 *
 *  Returns a pointer to the first byte past the end
 *   of this object (i.e. the start of the next object).
 *  Returns NULL on any error.
 */
unsigned char * asn_parse_string( unsigned char	*data,
                                  int *datalength,
                                  unsigned char *type,
                                  unsigned char *string,
                                  int *strlength)
{
/*
 * ASN.1 octet string ::= primstring | cmpdstring
 * primstring ::= 0x04 asnlength byte {byte}*
 * cmpdstring ::= 0x24 asnlength string {string}*
 */
    unsigned char *bufp = data;
    unsigned long	    asn_length;

    *type = *bufp++;
    bufp = asn_parse_length(bufp, &asn_length);
    if (bufp == NULL)
	return NULL;
    if ((int)(asn_length + (bufp - data)) > *datalength){
	ASNERROR("overflow of message");
	return NULL;
    }
    if ((int)asn_length > *strlength){
	ASNERROR("I don't support such long strings");
	return NULL;
    }
	// fixed
    memcpy((char *)string, (char *)bufp,  (int)asn_length);
    *strlength = (int)asn_length;
    *datalength -= (int)asn_length + (bufp - data);
    return bufp + asn_length;
};


/*
 * asn_build_string - Builds an ASN octet string object containing the input string.
 *  On entry, datalength is input as the number of valid bytes following
 *   "data".  On exit, it is returned as the number of valid bytes
 *   following the beginning of the next object.
 *
 *  Returns a pointer to the first byte past the end
 *   of this object (i.e. the start of the next object).
 *  Returns NULL on any error.
 */
unsigned char * asn_build_string( unsigned char *data,
                                  int *datalength,
                                  unsigned char type,
                                  unsigned char *string,
                                  int strlength)
{
/*
 * ASN.1 octet string ::= primstring | cmpdstring
 * primstring ::= 0x04 asnlength byte {byte}*
 * cmpdstring ::= 0x24 asnlength string {string}*
 * This code will never send a compound string.
 */
    data = asn_build_header(data, datalength, type, strlength);
    if (data == NULL)
	return NULL;
    if (*datalength < strlength)
	return NULL;
	// fixed
    memcpy((unsigned char *)data,(unsigned char *)string, strlength);
    *datalength -= strlength;
    return data + strlength;
};


/*
 * asn_parse_header - interprets the ID and length of the current object.
 *  On entry, datalength is input as the number of valid bytes following
 *   "data".  On exit, it is returned as the number of valid bytes
 *   in this object following the id and length.
 *
 *  Returns a pointer to the first byte of the contents of this object.
 *  Returns NULL on any error.
 */
unsigned char *asn_parse_header( unsigned char *data,
								 int *datalength,
                                 unsigned char *type)
{
    unsigned char *bufp = data;
	register int header_len;
    unsigned long	    asn_length;

    /* this only works on data types < 30, i.e. no extension octets */
    if (IS_EXTENSION_ID(*bufp)){
	ASNERROR("can't process ID >= 30");
	return NULL;
    }
    *type = *bufp;
    bufp = asn_parse_length(bufp + 1, &asn_length);
    if (bufp == NULL)
	return NULL;
    header_len = bufp - data;
    if ((int)(header_len + asn_length) > *datalength){
	ASNERROR("asn length too long");
	return NULL;
    }
    *datalength = (int)asn_length;
    return bufp;
};

/*
 * asn_build_header - builds an ASN header for an object with the ID and
 * length specified.
 *  On entry, datalength is input as the number of valid bytes following
 *   "data".  On exit, it is returned as the number of valid bytes
 *   in this object following the id and length.
 *
 *  This only works on data types < 30, i.e. no extension octets.
 *  The maximum length is 0xFFFF;
 *
 *  Returns a pointer to the first byte of the contents of this object.
 *  Returns NULL on any error.
 */
unsigned char * asn_build_header( unsigned char *data,
                                  int *datalength,
                                  unsigned char type,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?