asn1.cpp

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

CPP
1,758
字号
                                  int length)
{
    if (*datalength < 1)
	return NULL;
    *data++ = type;
    (*datalength)--;
    return asn_build_length(data, datalength, length);
    
};

/*
 * asn_build_sequence - builds an ASN header for a sequence 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_sequence( unsigned char *data,
                                    int *datalength,
                                    unsigned char type,
                                    int length)
{
    *datalength -= 4;
    if (*datalength < 0){
	*datalength += 4;	/* fix up before punting */
	return NULL;
    }
    *data++ = type;
    *data++ = (unsigned char)(0x02 | ASN_LONG_LEN);
    *data++ = (unsigned char)((length >> 8) & 0xFF);
    *data++ = (unsigned char)(length & 0xFF);
    return data;
};

/*
 * asn_parse_length - interprets the length of the current object.
 *  On exit, length contains the value of this length field.
 *
 *  Returns a pointer to the first byte after this length
 *  field (aka: the start of the data field).
 *  Returns NULL on any error.
 */
unsigned char * asn_parse_length( unsigned char *data,
                                  unsigned long  *length)
{
    unsigned char lengthbyte = *data;

    if (lengthbyte & ASN_LONG_LEN){
	lengthbyte &= ~ASN_LONG_LEN;	/* turn MSb off */
	if (lengthbyte == 0){
	    ASNERROR("We don't support indefinite lengths");
	    return NULL;
	}
	if (lengthbyte > sizeof(long)){
	    ASNERROR("we can't support data lengths that long");
	    return NULL;
	}
	// fixed
	memcpy((char *)length, (char *)data + 1, (int)lengthbyte);
	*length = ntohl(*length);
	*length >>= (8 * ((sizeof *length) - lengthbyte));
	return data + lengthbyte + 1;
    } else { /* short asnlength */
	*length = (long)lengthbyte;
	return data + 1;
    }
};

unsigned char *asn_build_length( unsigned char *data,
                                 int *datalength,
                                 int length)
{
    unsigned char    *start_data = data;

    /* no indefinite lengths sent */
    if (length < 0x80){
	if (*datalength < 1){
	    ASNERROR("build_length");
	    return NULL;
	}	    
	*data++ = (unsigned char)length;
    } else if (length <= 0xFF){
	if (*datalength < 2){
	    ASNERROR("build_length");
	    return NULL;
	}	    
	*data++ = (unsigned char)(0x01 | ASN_LONG_LEN);
	*data++ = (unsigned char)length;
    } else { /* 0xFF < length <= 0xFFFF */
	if (*datalength < 3){
	    ASNERROR("build_length");
	    return NULL;
	}	    
	*data++ = (unsigned char)(0x02 | ASN_LONG_LEN);
	*data++ = (unsigned char)((length >> 8) & 0xFF);
	*data++ = (unsigned char)(length & 0xFF);
    }
    *datalength -= (data - start_data);
    return data;

};

/*
 * asn_parse_objid - pulls an object indentifier out of an ASN object identifier 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.
 *
 *  "objid" is filled with the object identifier.
 *
 *  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_objid( unsigned char *data,
                                int *datalength,
                                unsigned char *type,
                                oid *objid,
                                int *objidlength)
{
/*
 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
 * subidentifier ::= {leadingbyte}* lastbyte
 * leadingbyte ::= 1 7bitvalue
 * lastbyte ::= 0 7bitvalue
 */
    unsigned char *bufp = data;
    oid *oidp = objid + 1;
    unsigned long subidentifier;
    long   length;
    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;
    }
    *datalength -= (int)asn_length + (bufp - data);

    /* Handle invalid object identifier encodings of the form 06 00 robustly */
    if (asn_length == 0)
	objid[0] = objid[1] = 0;

    length = asn_length;
    (*objidlength)--;	/* account for expansion of first byte */
    while (length > 0 && (*objidlength)-- > 0){
	subidentifier = 0;
	do {	/* shift and add in low order 7 bits */
	    subidentifier = (subidentifier << 7) + (*(unsigned char *)bufp & ~ASN_BIT8);
	    length--;
	} while (*(unsigned char *)bufp++ & ASN_BIT8);	/* last byte has high bit clear */
	if (subidentifier > (unsigned long)MAX_SUBID){
	    ASNERROR("subidentifier too long");
	    return NULL;
	}
	*oidp++ = (oid)subidentifier;
    }

    /*
     * The first two subidentifiers are encoded into the first component
     * with the value (X * 40) + Y, where:
     *	X is the value of the first subidentifier.
     *  Y is the value of the second subidentifier.
     */
    subidentifier = (unsigned long)objid[1];
    if (subidentifier == 0x2B){
	objid[0] = 1;
	objid[1] = 3;
    } else {
	objid[1] = (unsigned char)(subidentifier % 40);
	objid[0] = (unsigned char)((subidentifier - objid[1]) / 40);
    }

    *objidlength = (int)(oidp - objid);
    return bufp;
};

/*
 * asn_build_objid - Builds an ASN object identifier 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_objid( unsigned char *data,
                                int *datalength,
                                unsigned char type,
                                oid *objid,
                                int objidlength)
{
/*
 * ASN.1 objid ::= 0x06 asnlength subidentifier {subidentifier}*
 * subidentifier ::= {leadingbyte}* lastbyte
 * leadingbyte ::= 1 7bitvalue
 * lastbyte ::= 0 7bitvalue
 */
    unsigned char buf[MAX_OID_LEN];
    unsigned char *bp = buf;
    oid *op = objid;
    int    asnlength;
    unsigned long subid, mask, testmask;
    int bits, testbits;

    if (objidlength < 2){
	*bp++ = 0;
	objidlength = 0;
    } else {
	*bp++ = (unsigned char) (op[1] + (op[0] * 40));
	objidlength -= 2;
	op += 2;
    }

    while(objidlength-- > 0){
	subid = *op++;
	if (subid < 127){ /* off by one? */
	    *bp++ = (unsigned char )subid;
	} else {
	    mask = 0x7F; /* handle subid == 0 case */
	    bits = 0;
	    /* testmask *MUST* !!!! be of an unsigned type */
	    for(testmask = 0x7F, testbits = 0; testmask != 0;
		testmask <<= 7, testbits += 7){
		if (subid & testmask){	/* if any bits set */
		    mask = testmask;
		    bits = testbits;
		}
	    }
	    /* mask can't be zero here */
	    for(;mask != 0x7F; mask >>= 7, bits -= 7){
		/* fix a mask that got truncated above */
		if (mask == 0x1E00000)  
		    mask = 0xFE00000;
		*bp++ = (unsigned char)(((subid & mask) >> bits) | ASN_BIT8);
	    }
	    *bp++ = (unsigned char)(subid & mask);
	}
    }
    asnlength = bp - buf;
    data = asn_build_header(data, datalength, type, asnlength);
    if (data == NULL)
	return NULL;
    if (*datalength < asnlength)
	return NULL;
	// fixed
    memcpy((char *)data, (char *)buf,  asnlength);
    *datalength -= asnlength;
    return data + asnlength;
};

/*
 * asn_parse_null - Interprets an ASN null 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.
 *
 *  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_null(unsigned char	*data,
                              int *datalength,
                              unsigned char *type)
{
/*
 * ASN.1 null ::= 0x05 0x00
 */
    unsigned char   *bufp = data;
    unsigned long	    asn_length;

    *type = *bufp++;
    bufp = asn_parse_length(bufp, &asn_length);
    if (bufp == NULL)
	return NULL;
    if (asn_length != 0){
	ASNERROR("Malformed NULL");
	return NULL;
    }
    *datalength -= (bufp - data);
    return bufp + asn_length;
};


/*
 * asn_build_null - Builds an ASN null 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
 *   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_null( unsigned char *data,
                               int *datalength,
                               unsigned char type)
{
/*
 * ASN.1 null ::= 0x05 0x00
 */
    return asn_build_header(data, datalength, type, 0);
};

/*
 * asn_parse_bitstring - pulls a bitstring out of an ASN bitstring 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 bit 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_bitstring( unsigned char *data,
                                    int *datalength,
                                    unsigned char *type,
                                    unsigned char *string,
                                    int *strlength)
{
/*
 * bitstring ::= 0x03 asnlength unused {byte}*
 */
    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 bitstrings");
	return NULL;
    }
    if (asn_length < 1){
	ASNERROR("Invalid bitstring");
	return NULL;
    }
    //if (*bufp < 0 || *bufp > 7){
	//ASNERROR("Invalid bitstring");
	//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_bitstring - Builds an ASN bit 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_bitstring( unsigned char *data,
                                    int *datalength,
                                    unsigned char type,	
                                    unsigned char *string,
                                    int strlength)
{
/*
 * ASN.1 bit string ::= 0x03 asnlength unused {byte}*
 */
    //if (strlength < 1 || *string < 0 || *string > 7){
	//ASNERROR("Building invalid bitstring");
	//return NULL;
    //}

    data = asn_build_header(data, datalength, type, strlength);
    if (data == NULL)
	return NULL;
    if (*datalength < strlength)
	return NULL;
	// fixed
    memcpy((char *)data,(char *)string, strlength);
    *datalength -= strlength;
    return data + strlength;
};


/*
 * asn_parse_unsigned_int64 - pulls a 64 bit 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_int64(  unsigned char *data,
                                           int *datalength,
                                           unsigned char *type,
                                           struct counter64 *cp,
                                           int countersize)
{
/*
 * ASN.1 integer ::= 0x02 asnlength byte {byte}*
 */
    unsigned char *bufp = data;
    unsigned long	    asn_length;
    unsigned long low = 0, high = 0;
    int intsize = 4;
    
    if (countersize != sizeof(struct counter64)){
	ASNERROR("not right size");
	return NULL;
    }
    *type = *bufp++;
    bufp = asn_parse_length(bufp, &asn_length);
    if (bufp == NULL){
	ASNERROR("bad length");
	return NULL;
    }

⌨️ 快捷键说明

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