243 lines
8.9 KiB
C
243 lines
8.9 KiB
C
/************************************************************************/
|
|
/* 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;
|
|
}
|
|
|