Files
microser/mmslib/asn1/ard_int.c

491 lines
15 KiB
C
Raw Normal View History

2026-06-15 15:48:16 +08:00
/************************************************************************/
/* SISCO SOFTWARE MODULE HEADER *****************************************/
/************************************************************************/
/* (c) Copyright Systems Integration Specialists Company, Inc., */
/* 1986 - 2005, All Rights Reserved. */
/* */
/* PROPRIETARY AND CONFIDENTIAL */
/* */
/* MODULE NAME : ard_int.c */
/* PRODUCT(S) : ASN1DE */
/* */
/* MODULE DESCRIPTION : */
/* */
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */
/* */
/* MODIFICATION LOG : */
/* Date Who Rev Comments */
/* -------- --- ------ ------------------------------------------- */
/* 08/24/09 JRB 09 Fix signed int out of range error detection. */
/* Use separate signed & unsigned functions. */
/* Simplify negative value handling. */
/* 10/03/08 JRB 08 Fix crash by testing for asn1r_elmnt_len < 1.*/
/* 06/10/05 JRB 07 Use i64 suffix on WIN32, default to LL suffix*/
/* 03/03/05 EJV 06 Use LL suffix also on linux. */
/* 03/16/04 EJV 05 Added ST_(U)LONG typecast to logs,on some sys*/
/* ST_(U)INT32 can be (unsigned) long or int. */
/* asn1r_get_u8 (_u16): fixed potential problem.*/
/* 01/08/04 EJV 04 asn1r_get_int64: added define for sun. */
/* 12/20/01 JRB 03 Chg ASN1_CTXT to ASN1_DEC_CTXT. */
/* 09/13/99 MDE 02 Added SD_CONST modifiers */
/* 07/26/99 MDE 01 New module, derived from ad_int.c */
/************************************************************************/
#include "glbtypes.h"
#include "sysincs.h"
#include "asn1r.h"
#include "asn1log.h"
/************************************************************************/
/* For debug version, use a static pointer to avoid duplication of */
/* __FILE__ strings. */
#ifdef DEBUG_SISCO
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
#endif
/************************************************************************/
/************************************************************************/
static ST_RET asn1r_get_int32 (ASN1_DEC_CTXT *ac, ST_INT32 *ptr);
static ST_RET asn1r_get_uint32 (ASN1_DEC_CTXT *ac, ST_UINT32 *ptr);
#ifdef INT64_SUPPORT
static ST_RET asn1r_get_int64 (ASN1_DEC_CTXT *ac, ST_INT64 *ptr);
static ST_RET asn1r_get_uint64 (ASN1_DEC_CTXT *ac, ST_UINT64 *ptr);
#endif
/************************************************************************/
/* get_i8 */
/* Function to read a short integer from a message being decoded. */
/* Assumes asn1_field_ptr points to data (content field), and asn1_elmnt_len */
/* equals exactly one byte. Leaves pointer set to next data element. */
/* Returns 0 if OK, non-zero if error. */
/************************************************************************/
ST_RET asn1r_get_i8 (ASN1_DEC_CTXT *ac, ST_INT8 *ptr)
{
ST_INT32 value;
ST_RET ret;
ret = asn1r_get_int32 (ac, &value);
if (ret == SD_SUCCESS && (value > 127 || value < -128))
{
ALOG_NERR1 ("ASN.1 decode: Signed8 out of range (%ld)", (ST_LONG) value);
return (SD_FAILURE);
}
*ptr = (ST_CHAR) value;
return (ret);
}
/************************************************************************/
/* get_i16 */
/* Function to read an integer from a message being decoded. */
/* Assume asn1_field_ptr points to data, and asn1_elmnt_len */
/* equals one or two bytes. Leaves pointer set to next data element. */
/* Returns 0 if OK, non-zero if error. */
/************************************************************************/
ST_RET asn1r_get_i16 (ASN1_DEC_CTXT *ac, ST_INT16 *ptr)
{
ST_INT32 value;
ST_RET ret;
ret = asn1r_get_int32 (ac, &value);
if (ret == SD_SUCCESS && (value > 32767 || value < -32768))
{
ALOG_NERR1 ("ASN.1 decode: Signed16 out of range (%ld)", (ST_LONG) value);
return (SD_FAILURE);
}
*ptr = (ST_INT16) value;
return (ret);
}
/************************************************************************/
/* get_i32 */
/* Function to read a long integer from a message being decoded. */
/* Assumes asn1_field_ptr points to data, and asn1_elmnt_len */
/* equals one to four bytes. Leaves pointer set to next data element. */
/* Returns 0 if OK, non-zero if error. */
/************************************************************************/
ST_RET asn1r_get_i32 (ASN1_DEC_CTXT *ac, ST_INT32 *ptr)
{
ST_INT32 value;
ST_RET ret;
ret = asn1r_get_int32 (ac, &value);
*ptr = value;
return (ret);
}
/************************************************************************/
/* get_u8 */
/* Function to read an ASN.1 INTEGER from a message being decoded */
/* into a 1-byte unsigned char. Assumes asn1_field_ptr points to data */
/* field and asn1_elmnt_len has 1 or 2 bytes. Leaves asn1_field_ptr pointing to */
/* next data element. Returns 0 if OK, non-zero if error. */
/************************************************************************/
ST_RET asn1r_get_u8 (ASN1_DEC_CTXT *ac, ST_UCHAR *ptr)
{
ST_UINT32 value;
ST_RET ret;
ret = asn1r_get_uint32 (ac, &value);
if (ret == SD_SUCCESS && value > 0xFF)
{
ALOG_NERR1 ("ASN.1 decode: Unsigned16 out of range (%lu)", (ST_ULONG) value);
return (SD_FAILURE);
}
*ptr = (ST_UCHAR) value;
return (ret);
}
/************************************************************************/
/* get_u16 */
/* Function to read an ASN.1 INTEGER from a message being decoded */
/* into a 2-byte unsigned integer. Assumes asn1_field_ptr points to data */
/* field and asn1_elmnt_len has 1 to 3 bytes. Leaves asn1_field_ptr pointing to */
/* next data element. Returns 0 if OK, non-zero if error. */
/************************************************************************/
ST_RET asn1r_get_u16 (ASN1_DEC_CTXT *ac, ST_UINT16 *ptr)
{
ST_UINT32 value;
ST_RET ret;
ret = asn1r_get_uint32 (ac, &value);
if (ret == SD_SUCCESS && value > 0xFFFF)
{
ALOG_NERR1 ("ASN.1 decode: Unsigned16 out of range (%lu)", (ST_ULONG) value);
return (SD_FAILURE);
}
*ptr = (ST_UINT16) value;
return (ret);
}
/************************************************************************/
/* get_u32 */
/* Function to read an ASN.1 INTEGER from a message being decoded */
/* into a 4-byte unsigned ST_INT32. Assumes asn1_field_ptr points to data */
/* field and asn1_elmnt_len has 1 to 5 bytes. Leaves asn1_field_ptr pointing */
/* to next data element. Returns 0 if OK, non-zero if error. */
/************************************************************************/
ST_RET asn1r_get_u32 (ASN1_DEC_CTXT *ac, ST_UINT32 *ptr)
{
ST_UINT32 value;
ST_RET ret;
ret = asn1r_get_uint32 (ac, &value);
*ptr = value;
return (ret);
}
/************************************************************************/
/* Use this function ONLY for "signed" integers. */
/************************************************************************/
static ST_RET asn1r_get_int32 (ASN1_DEC_CTXT *ac, ST_INT32 *ptr)
{
/* NOTE: Use all "unsigned" variables so shifting & casting does not */
/* cause sign extension, then cast final result to ST_INT32. */
ST_UINT32 value; /* decoded value */
ST_UINT32 tmp;
ST_BOOLEAN positive;
ST_INT i;
#ifdef DEBUG_ASN1_DECODE
if (!ptr)
{
slogCallStack (sLogCtrl,
"get_i32: attempt to reference through a NULL pointer");
return(SD_FAILURE);
}
#endif
/* ASN.1 spec says 'integer' must be at least 1 octet */
if (ac->asn1r_elmnt_len < 1)
{
ALOG_ERR0 ("ASN.1 decode: length < 1 not allowed for integer");
return (SD_FAILURE);
}
/* Check to see if the ASN.1 data value is positive or negative */
if (*ac->asn1r_field_ptr & 0x80)
positive = SD_FALSE;
else
positive = SD_TRUE;
/* Large 'unsigned' values may be 5 bytes, with a leading 0. */
/* This value is 'signed', so it should NEVER be more than 4 bytes. */
i = ac->asn1r_elmnt_len;
if (i > 4)
{
ALOG_NERR0 ("ASN.1 decode: invalid 'signed' integer encoding (more than 4 bytes)");
return (SD_FAILURE);
}
/* Read the value into a ST_UINT32, shifting as we go */
if (!positive)
value = 0xFFFFFF00; /* negative value, start with high bits set */
else
value = 0; /* positive value, start with 0 */
while (SD_TRUE)
{
/* asn1r_field_ptr is (ST_UCHAR *), so this cast should NEVER sign extend.*/
tmp = (ST_UINT32) *(ac->asn1r_field_ptr++);
value |= tmp;
if (--i == 0)
break;
value <<= 8; /* more bytes to decode. Make room for next byte.*/
}
/* Finally, after all shifting & masking, cast it to 'signed' value. */
*ptr = (ST_INT32) value;
return (SD_SUCCESS);
}
/************************************************************************/
/* Use this function ONLY for "unsigned" integers. */
/************************************************************************/
static ST_RET asn1r_get_uint32 (ASN1_DEC_CTXT *ac, ST_UINT32 *ptr)
{
ST_UINT32 value; /* decoded value */
ST_UINT32 tmp;
ST_INT i;
#ifdef DEBUG_ASN1_DECODE
if (!ptr)
{
slogCallStack (sLogCtrl,
"get_u32: attempt to reference through a NULL pointer");
return(SD_FAILURE);
}
#endif
/* ASN.1 spec says 'integer' must be at least 1 octet */
if (ac->asn1r_elmnt_len < 1)
{
ALOG_ERR0 ("ASN.1 decode: length < 1 not allowed for integer");
return (SD_FAILURE);
}
/* ASN.1 data value MUST BE positive. */
if (*ac->asn1r_field_ptr & 0x80)
{
ALOG_NERR0 ("ASN.1 decode: Negative number received for unsigned integer");
return (SD_FAILURE);
}
/* Large 'unsigned' values may be 5 bytes, with a leading 0. */
/* If so, we strip the leading 0. */
i = ac->asn1r_elmnt_len;
if (i > 5)
{
ALOG_NERR0 ("ASN.1 decode: invalid UINT32 encoding (more than 5 bytes)");
return (SD_FAILURE);
}
if (i == 5) /* Large positive number, first byte must be 0. */
{
if (*ac->asn1r_field_ptr != 0)
{
ALOG_NERR0 ("ASN.1 decode: invalid UINT32 encoding (5 bytes but first byte != 0)");
return (SD_FAILURE);
}
++ac->asn1r_field_ptr; /* skip the leading 0 */
--i;
}
/* Read the value into a ST_UINT32, shifting as we go */
value = 0;
while (SD_TRUE)
{
/* asn1r_field_ptr is (ST_UCHAR *), so this cast should NEVER sign extend.*/
tmp = (ST_UINT32) *(ac->asn1r_field_ptr++);
value |= tmp;
if (--i == 0)
break;
value <<= 8; /* more bytes to decode. Make room for next byte.*/
}
*ptr = value;
return (SD_SUCCESS);
}
/************************************************************************/
#ifdef INT64_SUPPORT
/************************************************************************/
/************************************************************************/
ST_RET asn1r_get_u64 (ASN1_DEC_CTXT *ac, ST_UINT64 *ptr)
{
ST_UINT64 value;
ST_RET ret;
ret = asn1r_get_uint64 (ac, &value);
*ptr = value;
return (ret);
}
/************************************************************************/
ST_RET asn1r_get_i64 (ASN1_DEC_CTXT *ac, ST_INT64 *ptr)
{
ST_INT64 value;
ST_RET ret;
ret = asn1r_get_int64 (ac, &value);
*ptr = value;
return (ret);
}
/************************************************************************/
/* Use this function ONLY for "signed" integers. */
/************************************************************************/
static ST_RET asn1r_get_int64 (ASN1_DEC_CTXT *ac, ST_INT64 *ptr)
{
/* NOTE: Use all "unsigned" variables so shifting & casting does not */
/* cause sign extension, then cast final result to ST_INT64. */
ST_UINT64 value; /* decoded value */
ST_UINT64 tmp;
ST_BOOLEAN positive;
ST_INT i;
#ifdef DEBUG_ASN1_DECODE
if (!ptr)
{
slogCallStack (sLogCtrl,
"get_i64: attempt to reference through a NULL pointer");
return(SD_FAILURE);
}
#endif
/* ASN.1 spec says 'integer' must be at least 1 octet */
if (ac->asn1r_elmnt_len < 1)
{
ALOG_ERR0 ("ASN.1 decode: length < 1 not allowed for integer");
return (SD_FAILURE);
}
/* Check to see if the ASN.1 data value is positive or negative */
if (*ac->asn1r_field_ptr & 0x80)
positive = SD_FALSE;
else
positive = SD_TRUE;
/* Large 'unsigned' values may be 9 bytes, with a leading 0. */
/* This value is 'signed', so it should NEVER be more than 8 bytes. */
i = ac->asn1r_elmnt_len;
if (i > 8)
{
ALOG_NERR0 ("ASN.1 decode: invalid 'signed' integer encoding (more than 8 bytes)");
return (SD_FAILURE);
}
/* Read the value into a ST_UINT64, shifting as we go */
if (!positive)
{
#if defined(_WIN32)
value = 0xffffffffffffff00i64; /* negative value, start with high bits set*/
#else
value = 0xffffffffffffff00LL; /* negative value, start with high bits set*/
#endif
}
else
value = 0; /* positive value, start with 0 */
while (SD_TRUE)
{
/* asn1r_field_ptr is (ST_UCHAR *), so this cast should NEVER sign extend.*/
tmp = (ST_UINT64) *(ac->asn1r_field_ptr++);
value |= tmp;
if (--i == 0)
break;
value <<= 8; /* more bytes to decode. Make room for next byte.*/
}
/* Finally, after all shifting & masking, cast it to 'signed' value. */
*ptr = (ST_INT64) value;
return (SD_SUCCESS);
}
/************************************************************************/
/* Use this function ONLY for "unsigned" integers. */
/************************************************************************/
static ST_RET asn1r_get_uint64 (ASN1_DEC_CTXT *ac, ST_UINT64 *ptr)
{
ST_UINT64 value; /* decoded value */
ST_UINT64 tmp;
ST_INT i;
#ifdef DEBUG_ASN1_DECODE
if (!ptr)
{
slogCallStack (sLogCtrl,
"get_u64: attempt to reference through a NULL pointer");
return(SD_FAILURE);
}
#endif
/* ASN.1 spec says 'integer' must be at least 1 octet */
if (ac->asn1r_elmnt_len < 1)
{
ALOG_ERR0 ("ASN.1 decode: length < 1 not allowed for integer");
return (SD_FAILURE);
}
/* ASN.1 data value MUST BE positive. */
if (*ac->asn1r_field_ptr & 0x80)
{
ALOG_NERR0 ("ASN.1 decode: Negative number received for unsigned integer");
return (SD_FAILURE);
}
/* Large 'unsigned' values may be 9 bytes, with a leading 0. */
/* If so, we strip the leading 0. */
i = ac->asn1r_elmnt_len;
if (i > 9)
{
ALOG_NERR0 ("ASN.1 decode: invalid UINT64 encoding (more than 9 bytes)");
return (SD_FAILURE);
}
if (i == 9) /* Large positive number, first byte must be 0. */
{
if (*ac->asn1r_field_ptr != 0)
{
ALOG_NERR0 ("ASN.1 decode: invalid UINT64 encoding (9 bytes but first byte != 0)");
return (SD_FAILURE);
}
++ac->asn1r_field_ptr; /* skip the leading 0 */
--i;
}
/* Read the value into a ST_UINT64, shifting as we go */
value = 0;
while (SD_TRUE)
{
/* asn1r_field_ptr is (ST_UCHAR *), so this cast should NEVER sign extend.*/
tmp = (ST_UINT64) *(ac->asn1r_field_ptr++);
value |= tmp;
if (--i == 0)
break;
value <<= 8; /* more bytes to decode. Make room for next byte.*/
}
*ptr = value;
return (SD_SUCCESS);
}
/************************************************************************/
#endif /* #ifdef INT64_SUPPORT */
/************************************************************************/