Files
microser/mmslib/asn1/ard_bstr.c

243 lines
8.9 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 - 2001, All Rights Reserved. */
/* */
/* PROPRIETARY AND CONFIDENTIAL */
/* */
/* MODULE NAME : ard_bstr.c */
/* PRODUCT(S) : ASN1DE */
/* */
/* MODULE DESCRIPTION : */
/* */
/* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */
/* */
/* MODIFICATION LOG : */
/* Date Who Rev Comments */
/* -------- --- ------ ------------------------------------------- */
/* 07/21/09 JRB 12 Set asn1r_bitstr_truncated flag for primitive*/
/* OR constructed bitstring. */
/* 07/21/09 JRB 11 Constructed bitstr code: enable it ALWAYS, */
/* overhaul to make sure segments are multiples */
/* of 8 bits, fix it to truncate. */
/* 07/07/09 JRB 10 asn1r_get_bitstr: fix bitcount if truncated. */
/* 04/21/08 JRB 09 Add cast to fix warning. */
/* 03/17/04 RKR 08 Changed thisFileName */
/* 03/11/04 GLB 07 Remove "thisFileName" */
/* 03/31/03 JRB 06 asn1r_get_bitstr: add max_bits arg & truncate*/
/* bitstr if max_bits exceeded. */
/* 03/05/02 JRB 05 Eliminate warnings. */
/* 12/20/01 JRB 04 Chg ASN1_CTXT to ASN1_DEC_CTXT. */
/* 12/12/01 JRB 03 Changes to compile MMS-EASE */
/* 09/13/99 MDE 02 Added SD_CONST modifiers */
/* 07/26/99 MDE 01 New module, derived from ard_bstr.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. */
#if defined(DEBUG_SISCO)
SD_CONST static ST_CHAR *SD_CONST thisFileName = __FILE__;
#endif
/************************************************************************/
/************************************************************************/
static ST_VOID _dec_bitstr_cstr (ASN1_DEC_CTXT *ac, ST_UINT16 id_code);
/************************************************************************/
/* get_bitstr */
/* Function to read a primitive bitstring from an ASN.1 message. */
/* Truncate bitstring if it exceeds "max_bits". */
/************************************************************************/
ST_RET asn1r_get_bitstr (ASN1_DEC_CTXT *ac, ST_UCHAR *bit_ptr, ST_INT max_bits)
{
ST_INT i;
#ifdef DEBUG_ASN1_DECODE
if (!bit_ptr)
{
slogCallStack (sLogCtrl,
"get_: attempt to reference through a NULL pointer");
return(SD_FAILURE);
}
#endif
ac->asn1r_bitstr_truncated = SD_FALSE; /* CRITICAL: init "truncated" flag*/
if (ac->asn1r_elmnt_len < 1) /* For element length of 0, return error code. */
return (SD_FAILURE);
i = *(ac->asn1r_field_ptr++);
if (i>7 || i<0)
return (2); /* Return error code for bad unused-bits value. */
if (ac->asn1r_elmnt_len == 1) /* When there is only the unused-bits octet, */
{ /* it must = 0, and there are no data bits. */
if (i!=0)
return (2);
ac->asn1r_bitcount = 0;
}
else /* Treat normal case where there are data bits. */
{
ac->asn1r_bitcount = ((ac->asn1r_elmnt_len-1)*8 - i); /* Compute # data bits. */
/* If caller imposed a limit, truncate. */
if (max_bits != 0 && ac->asn1r_bitcount > max_bits)
{
ac->asn1r_bitcount = max_bits; /* truncated */
ac->asn1r_bitstr_truncated = SD_TRUE;
}
/* Copy bitstring to user buffer */
bstrcpy (bit_ptr, ac->asn1r_field_ptr, ac->asn1r_bitcount);
ac->asn1r_field_ptr += (ac->asn1r_elmnt_len - 1); /* point to next*/
}
return (SD_SUCCESS);
}
/************************************************************************/
/* get_bitstr_cstr */
/* Function to setup to get a constructed bitstring. */
/************************************************************************/
ST_VOID asn1r_get_bitstr_cstr (ASN1_DEC_CTXT *ac, ST_INT bits, ST_UCHAR *ptr)
{
#ifdef DEBUG_ASN1_DECODE
if (!ptr)
{
slogCallStack (sLogCtrl,
"get_bitstr_cstr: attempt to reference through a NULL pointer");
return;
}
#endif
ac->asn1r_max_bits = bits; /* max allowed # bits */
ac->_ad_bitptr = ptr; /* pointer to bit storage area */
*ac->_ad_bitptr = 0; /* zero first byte of user's storage area */
ac->asn1r_bitcount = 0; /* running bit count */
ac->asn1r_bitstr_truncated = SD_FALSE; /* CRITICAL: init "truncated" flag*/
ac->asn1r_u_id_fun = _dec_bitstr_cstr; /* universal until bitstr done */
ac->asn1r_c_id_fun = asn1r_class_err; /* no more context */
ac->asn1r_a_id_fun = asn1r_class_err; /* or application */
ac->asn1r_p_id_fun = asn1r_class_err; /* or private */
ac->asn1r_save_method = ac->asn1r_decode_method;
ac->asn1r_decode_method = ASN1_CLASS_METHOD;
ac->_asn1r_fun_save = ac->asn1r_decode_done_fun; /* save the previous done fun */
ac->asn1r_decode_done_fun = asn1r_done_err; /* can't be done for now */
ac->_asn1r_cstr_done_save = ac->asn1r_c_done_fun[ac->asn1r_msg_level];
ac->asn1r_c_done_fun[ac->asn1r_msg_level] = asn1r_chk_getcstr_done;
}
/************************************************************************/
/* _dec_bitstr_cstr */
/* Function to decode asn.1 constructor bitstrings. */
/* NOTE: last segment may be any length but other segments must be */
/* multiple of 8 bits. We don't know which segment is last until the */
/* decode completes. We assume any segment that is NOT a multiple of */
/* 8 bits must be the last, so if any segment is received after that, */
/* it is a protocol error. */
/************************************************************************/
static ST_VOID _dec_bitstr_cstr (ASN1_DEC_CTXT *ac, ST_UINT16 id_code)
{
ST_INT numbytes;
ST_INT numbits;
ST_UCHAR unused_bits; /* # of unused bits in last byte */
ALOG_DEC0 ("_dec_bitstr_cstr");
if ((id_code & BITS_CODE) != BITS_CODE)
{ /* Protocol error - invalid ID Code. */
ALOG_NERR0 ("ASN.1 decode: unexpected tag");
asn1r_set_dec_err(ac, ASN1E_UNEXPECTED_TAG);
return;
}
if (ac->asn1r_constr_elmnt) /* Don't do anything for constructors */
{
ac->asn1r_c_done_fun[ac->asn1r_msg_level] = NULL;
return;
}
/* Handle primitive bitstrings */
if (ac->asn1r_bitstr_truncated)
{
/* Already truncated when earlier segment decoded. Just skip over this data.*/
ac->asn1r_field_ptr += ac->asn1r_elmnt_len;
return;
}
/* If bitcount before adding this segment is not multiple of 8, the */
/* previous segment length was illegal. */
if (ac->asn1r_bitcount % 8)
{ /* Protocol error */
ALOG_NERR0 ("ASN.1 decode: constructed bitstring previous segment length not multiple of 8");
asn1r_set_dec_err(ac, ASN1E_INVALID_BITSTR);
return;
}
/* check length. Handle most common case first. */
if (ac->asn1r_elmnt_len > 1)
{
unused_bits = *ac->asn1r_field_ptr; /* read the unused-bits byte. */
if (unused_bits > 7)
{ /* Protocol error */
ALOG_NERR0 ("ASN.1 decode: constructed bitstring unused bits > 7");
asn1r_set_dec_err(ac, ASN1E_INVALID_BITSTR);
return;
}
/* # of bytes of data does not include the "unused bits" byte. */
numbytes = (ST_INT16) (ac->asn1r_elmnt_len - 1);
numbits = numbytes*8 - unused_bits;
if (ac->asn1r_bitcount + numbits > ac->asn1r_max_bits)
{
/* Truncate. Recalculate numbits, numbytes. */
numbits = ac->asn1r_max_bits - ac->asn1r_bitcount;
numbytes = numbits / 8;
if (numbits % 8)
numbytes++;
ac->asn1r_bitstr_truncated = SD_TRUE; /* set "truncated" flag */
}
/* Copy bitstring data (at ac->asn1r_field_ptr + 1) to user buffer */
if (numbits)
bstrcpy (ac->_ad_bitptr, ac->asn1r_field_ptr + 1, numbits);
ac->_ad_bitptr += numbytes; /* adjust pointer */
ac->asn1r_bitcount += numbits; /* adjust bit count */
}
else if (ac->asn1r_elmnt_len == 1) /* ONLY unused-bits byte. Must be 0.*/
{
unused_bits = *ac->asn1r_field_ptr; /* read the unused-bits byte. */
if (unused_bits != 0)
{ /* Protocol error */
ALOG_NERR0 ("ASN.1 decode: bitstring no data. unused bits != 0");
asn1r_set_dec_err(ac, ASN1E_INVALID_BITSTR);
return;
}
}
else /* (ac->asn1r_elmnt_len < 1) */
{ /* Protocol error */
ALOG_NERR1 ("ASN.1 decode: bitstring element length = %d illegal",
ac->asn1r_elmnt_len);
asn1r_set_dec_err(ac, ASN1E_INVALID_BITSTR);
return;
}
/* CRITICAL: update field_ptr only here. */
ac->asn1r_field_ptr += ac->asn1r_elmnt_len;
return;
}