/************************************************************************/ /* SISCO SOFTWARE MODULE HEADER *****************************************/ /************************************************************************/ /* (c) Copyright Systems Integration Specialists Company, Inc., */ /* 1997 - 2006, All Rights Reserved. */ /* */ /* PROPRIETARY AND CONFIDENTIAL */ /* */ /* MODULE NAME : mmsdatat.c */ /* PRODUCT(S) : none */ /* */ /* MODULE DESCRIPTION : */ /* This module contains the functions employed by the virtual */ /* machine for parsing an ASN.1 data string and creating the */ /* run-time type specification from it. */ /* Adapted from mmsdata.c */ /* */ /* GLOBAL FUNCTIONS DEFINED IN THIS MODULE : */ /* */ /* MODIFICATION LOG : */ /* Date Who Rev Comments */ /* -------- --- ------ ------------------------------------------- */ /* 03/17/08 JRB 19 Del m_use_long_ints flag & assume smallest */ /* integer is 4 bytes. */ /* 02/19/07 JRB 18 Add error log message. */ /* 03/22/06 EJV 17 Changed RT_GENERAL_TIME st_size and el_len to*/ /* sizeof(time_t) (VS 2005 has 64-bit time_t).*/ /* 01/30/06 GLB 16 Integrated porting changes for VMS */ /* 10/27/03 JRB 15 Assume all UTF8strings are variable-length. */ /* Add code to adjust len for array of UTF8str..*/ /* 10/16/03 MDE 14 Fixed leak for data conversion error */ /* 05/08/03 JRB 13 Fix TAG_ADD for "array" of RT_UTF8_STRING. */ /* 04/02/03 JRB 12 Add UTF8string support (see RT_UTF8_STRING). */ /* 12/20/01 JRB 11 Converted to use ASN1R (re-entrant ASN1) */ /* 11/15/01 EJV 10 Added support for new MMS type UtcTime. */ /* 10/06/00 MDE 09 Now set asn1_decode_method */ /* 04/20/00 JRB 08 Undo last chg, fix mms_vvar.h instead. Lint. */ /* 10/13/99 RKR 07 Added SD_CONST to function headers */ /* 09/13/99 MDE 06 Added SD_CONST modifiers */ /* 06/03/98 MDE 05 Allow for 0 length variable length items */ /* 03/12/98 MDE 04 Fixed 'loops' change - whoops! */ /* 02/10/98 MDE 03 No longer use runtime type 'loops' element */ /* 08/15/97 MDE 02 BTOD handling changes */ /* 07/03/97 MDE 01 Fixed problem w/structures */ /* 04/02/97 DTL 7.00 MMSEASE 7.0 release. See MODL70.DOC for */ /* history. */ /************************************************************************/ #include "glbtypes.h" #include "sysincs.h" #include "glbsem.h" #include "mmsdefs.h" #include "mms_pvar.h" #include "mms_vvar.h" #include "asn1defs.h" #include "mem_chk.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_VOID assign_tags (ASN1_DEC_CTXT *aCtx); static int init_new_RT (ASN1_DEC_CTXT *aCtx, ST_UCHAR tag, ST_INT el_len); #if 0 /* Constructed bitstrings and octetstrings not supported */ static ST_VOID get_bstr_cstr (ASN1_DEC_CTXT *aCtx); /* for constructed bitstrings */ static ST_VOID get_ostr_cstr (ASN1_DEC_CTXT *aCtx); /* for constructed octetstrings */ static ST_VOID bs_cstr_done (ASN1_DEC_CTXT *aCtx); static ST_VOID os_cstr_done (ASN1_DEC_CTXT *aCtx); #endif static ST_VOID get_bool_prim (ASN1_DEC_CTXT *aCtx); /* for boolean primitives */ static ST_VOID get_bitstr_prim (ASN1_DEC_CTXT *aCtx); /* for bitstring primitives */ static ST_VOID get_int_prim (ASN1_DEC_CTXT *aCtx); /* for integer primitives */ static ST_VOID get_uint_prim (ASN1_DEC_CTXT *aCtx); /* for unsigned integers */ static ST_VOID get_float_prim (ASN1_DEC_CTXT *aCtx); /* for float primitives */ static ST_VOID get_octstr_prim (ASN1_DEC_CTXT *aCtx); /* for octet string primitives */ static ST_VOID get_vstr_prim (ASN1_DEC_CTXT *aCtx); /* for visible string primitives*/ static ST_VOID get_gtime_prim (ASN1_DEC_CTXT *aCtx); /* for generalized time */ static ST_VOID get_btime_prim (ASN1_DEC_CTXT *aCtx); /* for binary time primitives */ static ST_VOID get_bcd_prim (ASN1_DEC_CTXT *aCtx); /* for binary coded decimal */ static ST_VOID get_utc_time_prim (ASN1_DEC_CTXT *aCtx); /* for UTC time primitives */ static ST_VOID get_utf8_prim (ASN1_DEC_CTXT *aCtx); /* for UTF8string primitives */ static ST_VOID arr_start (ASN1_DEC_CTXT *aCtx); static ST_VOID str_start (ASN1_DEC_CTXT *aCtx); static ST_VOID arr_done_fun (ASN1_DEC_CTXT *aCtx); static ST_VOID str_done_fun (ASN1_DEC_CTXT *aCtx); static ST_VOID err_clean_fun (ASN1_DEC_CTXT *aCtx, ST_RET err_code); typedef enum { UNDEF, STRUCT, ARRAY } ConstrType; /* Constructor types */ static RUNTIME_TYPE *rt_base; /* Base ptr for runtime array */ static RUNTIME_TYPE *cur_rt; /* Current runtime element ptr */ static RUNTIME_TYPE *nxt_un_rt; /* Next unused RT el in buffer */ static RUNTIME_TYPE *rt_EOB_ptr; /* One past end of RT buffer. */ static int local_alloc_flag; /* Block pointer for arrs & structs */ static RUNTIME_TYPE *rt_blk_start[ASN1_MAX_LEVEL]; static ConstrType constr_type[ASN1_MAX_LEVEL]; /* Cstr type */ static ST_INT arr_loop_level; static ST_INT *arr_loops; /* The following defines specify the various error codes that are used */ /* in ms_asn1_to_locl and its subordinate functions. These are in ad- */ /* dition to the error codes that can be generated by ASN1DE internally,*/ /* and both translate into return values that are one greater than the */ /* error codes themselves. */ #define BAD_DATA 100 /* Data not consistent with */ /* type specification. */ #define INTERNAL 101 /* Type specif'n bad, not data. */ /************************************************************************/ /************************************************************************/ ST_RET ms_asn1_data_to_locl (ST_UCHAR *asn1_data, ST_INT asn1_data_len, ST_VOID **data_dest, ST_INT *data_dest_len, RUNTIME_TYPE **rt, ST_INT *t_len) { ST_RET rc; RUNTIME_TYPE *rt_in; /* First, build runtime from data string */ rt_in = *rt; rc = ms_asn1_data_to_runtime (rt, t_len, asn1_data, asn1_data_len); if (rc != SD_SUCCESS) return (rc); /* verify that the supplied data buffer is big enough */ if (*data_dest && *data_dest_len < (*rt)->offset_to_last) { if (!rt_in) /* RT table was chk_calloc'd */ chk_free (*rt); return (MVE_DATA_SPACE); } if (!*data_dest) { *data_dest_len = (*rt)->offset_to_last; /* Variable length items can have a data length of 0 */ if (*data_dest_len) { *data_dest = chk_calloc (1, (*rt)->offset_to_last); /* OK, go ahead and do the data conversion */ rc = ms_asn1_to_local (*rt, *t_len, asn1_data, asn1_data_len, (ST_CHAR *) *data_dest); if (rc) { chk_free (*data_dest); if (!rt_in) /* RT table was chk_calloc'd */ chk_free (*rt); } } else *data_dest = chk_calloc (1, 1); } else /* OK, go ahead and do the data conversion */ { rc = ms_asn1_to_local (*rt, *t_len, asn1_data, asn1_data_len, (ST_CHAR *) *data_dest); if (rc && !rt_in) /* Error and RT table was chk_calloc'd */ chk_free (*rt); } return (rc); } /************************************************************************/ /* ms_asn1_data_to_runtime */ /* Creates a run-time data defn table from the input ASN.1 data string. */ /* Input parameters: */ /* RUNTIME_TYPE **tptr Pointer^2 to runtime buffer. */ /* ST_INT *t_len Length of runtime buffer, in runtime elements. */ /* ST_UCHAR *asn1ptr Pointer to input ASN.1 string */ /* ST_INT asn1len Length of ASN.1 string, in bytes. */ /* Returns: SD_SUCCESS, SD_FAILURE or INTERNAL. If SD_FAILURE, aCtx->asn1r_pdu_dec_err */ /* has the specific error code. */ /* Output globals: aCtx->asn1r_decode_done_fun */ /* Static variables set: rt_base, rt_EOB_ptr, cur_rt, nxt_un_rt */ /************************************************************************/ ST_RET ms_asn1_data_to_runtime (RUNTIME_TYPE **tptr, ST_INT *t_len, ST_UCHAR *asn1ptr, ST_INT asn1_len) { ST_RET ret; ST_INT arr_loop_buf[ASN1_MAX_LEVEL]; ASN1_DEC_CTXT localDecCtx; /* For readability, use "aCtx" to access this.*/ ASN1_DEC_CTXT *aCtx = &localDecCtx; memset (aCtx, 0, sizeof (ASN1_DEC_CTXT)); /* CRITICAL: start clean. */ local_alloc_flag = SD_FALSE; if (tptr == NULL) /* What? Parameter error, fix that. */ { return (MVE_RT_TYPE); } S_LOCK_COMMON_RESOURCES (); arr_loop_level = 0; arr_loops = arr_loop_buf; if (*tptr != NULL) { /* Type buffer already allocated, use it. */ rt_base = *tptr; /* Init pointer to runtime buffer. */ if (*t_len <= 0) /* Check size. */ { S_UNLOCK_COMMON_RESOURCES (); return (MVE_RT_TYPE); /* Parameter error. */ } else rt_EOB_ptr = rt_base + *t_len; /* Init end-of-buffer pointer */ } else /* Allocate a default-size buffer here. */ { rt_base = (RUNTIME_TYPE *) chk_calloc (m_rt_type_limit, sizeof (RUNTIME_TYPE)); rt_EOB_ptr = rt_base + m_rt_type_limit; local_alloc_flag = SD_TRUE; } cur_rt = nxt_un_rt = rt_base; rt_blk_start[0] = rt_base; /* Starting block for level 0 is first block. */ constr_type[0] = UNDEF; /* Constructed type initializes to UNDEF. */ /* These variables are used by the tag routines */ /* to build the runtime type table. */ aCtx->asn1r_decode_method = ASN1_TAG_METHOD; assign_tags (aCtx); /* Assign tags. First type can be anything. */ aCtx->asn1r_decode_done_fun = NULL; aCtx->asn1r_err_fun = err_clean_fun; asn1r_decode_asn1 (aCtx, asn1ptr, asn1_len); /* Build the type table. */ *tptr = rt_base; /* Local buffer de-allocated on error. */ if (rt_base != NULL) /* Check for error to prevent doing */ { /* arithmetic with NULL pointers. */ *t_len = nxt_un_rt - rt_base; ms_rt_size_calc (rt_base, *t_len); /* Fix up element offsets in table */ } else *t_len = 0; ret = (aCtx->asn1r_pdu_dec_err == NO_DECODE_ERR) ? SD_SUCCESS : MVE_DATA_TO_RT ; S_UNLOCK_COMMON_RESOURCES (); return (ret); } /************************************************************************/ /* assign_tags */ /* Function to assign tags to the ASN1DE tools based on what's expected */ /* in the runtime_type definition table. At the beginning of the 'Data'*/ /* entity, a DataAccessError type is allowed. WARNING: This function */ /* requires that the current rt_block NOT be an end-of-array or end-of- */ /* structure rt_block. If so, it will return an error. */ /************************************************************************/ static ST_VOID assign_tags (ASN1_DEC_CTXT *aCtx) { /* There are two possible cases here: */ /* 1.) We are parsing through terra incognita and don't know */ /* what to expect (yet). All possible tags are legal. */ /* Set up to build type definitions for what we find. */ /* 2.) We are parsing through the 2nd or later element of an */ /* array and know what tag we should get next. If the */ /* array is a sub-array of an enveloping array, we will */ /* have an element count for it; check that too. Verify */ /* tags against what we expect to see. */ if (cur_rt < nxt_un_rt) /* if this is the 2nd or later element */ { /* of an array & types are defined, */ if (cur_rt->el_tag == RT_ARR_END) /* treat case of array ending */ { /* Only possible if we've seen this array before as */ /* an element of an enveloping array, otherwise */ /* there would be no RT_ARR_END runtime record yet. */ if (--arr_loops[arr_loop_level] > 0) /* if need to do next ar elmnt */ cur_rt -= cur_rt->u.arr.num_rt_blks; } /* mv cur_rt to start of arr */ switch (cur_rt->el_tag) { case RT_ARR_START : ASN1R_TAG_ADD (aCtx, CTX|CONSTR,1,arr_start); /* expecting an array cstr */ break; case RT_STR_START : ASN1R_TAG_ADD (aCtx, CTX|CONSTR,2,str_start); /* expecting a struct cstr */ break; case RT_BOOL : ASN1R_TAG_ADD (aCtx, CTX,3,get_bool_prim); break; case RT_BIT_STRING : ASN1R_TAG_ADD (aCtx, CTX,4,get_bitstr_prim); #if 0 /* Constructed bitstrings and octetstrings not supported */ ASN1R_TAG_ADD (aCtx, CTX|CONSTR,4,get_bstr_cstr); #endif break; case RT_INTEGER : ASN1R_TAG_ADD (aCtx, CTX,5,get_int_prim); break; case RT_UNSIGNED : ASN1R_TAG_ADD (aCtx, CTX,6,get_uint_prim); break; #ifdef FLOAT_DATA_SUPPORT case RT_FLOATING_POINT : ASN1R_TAG_ADD (aCtx, CTX,7,get_float_prim); break; #endif case RT_OCTET_STRING : ASN1R_TAG_ADD (aCtx, CTX,9,get_octstr_prim); #if 0 /* Constructed bitstrings and octetstrings not supported */ ASN1R_TAG_ADD (aCtx, CTX|CONSTR,9,get_ostr_cstr); #endif break; case RT_VISIBLE_STRING : ASN1R_TAG_ADD (aCtx, CTX,10,get_vstr_prim); break; #ifdef TIME_DATA_SUPPORT case RT_GENERAL_TIME : ASN1R_TAG_ADD (aCtx, CTX,11,get_gtime_prim); break; #endif #ifdef BTOD_DATA_SUPPORT case RT_BINARY_TIME : ASN1R_TAG_ADD (aCtx, CTX,12,get_btime_prim); break; #endif case RT_BCD : ASN1R_TAG_ADD (aCtx, CTX,13,get_bcd_prim); break; case RT_UTC_TIME : ASN1R_TAG_ADD (aCtx, CTX,17,get_utc_time_prim); break; case RT_UTF8_STRING : ASN1R_TAG_ADD (aCtx, CTX,RT_UTF8_STRING,get_utf8_prim); break; case RT_ARR_END : /* array done */ aCtx->asn1r_c_done_fun[aCtx->asn1r_msg_level] = arr_done_fun; /* the arr cstr must be done*/ break; case RT_STR_END : /* structure done */ aCtx->asn1r_c_done_fun[aCtx->asn1r_msg_level] = str_done_fun; /* the str cstr must be done*/ break; default : /* should not be any other tag */ MLOG_ERR0 ("Bad tag in runtime type"); asn1r_set_dec_err (aCtx, INTERNAL); return; break; } } else /* In terra incognita, next element can be anything */ { /* Allow for any type of data in the data string. */ ASN1R_TAG_ADD (aCtx, CTX|CONSTR,1,arr_start); ASN1R_TAG_ADD (aCtx, CTX|CONSTR,2,str_start); ASN1R_TAG_ADD (aCtx, CTX,3,get_bool_prim); ASN1R_TAG_ADD (aCtx, CTX,4,get_bitstr_prim); #if 0 /* Constructed bitstrings and octetstrings not supported */ ASN1R_TAG_ADD (aCtx, CTX|CONSTR,4,get_bstr_cstr); #endif ASN1R_TAG_ADD (aCtx, CTX,5,get_int_prim); ASN1R_TAG_ADD (aCtx, CTX,6,get_uint_prim); ASN1R_TAG_ADD (aCtx, CTX,7,get_float_prim); ASN1R_TAG_ADD (aCtx, CTX,9,get_octstr_prim); #if 0 /* Constructed bitstrings and octetstrings not supported */ ASN1R_TAG_ADD (aCtx, CTX|CONSTR,9,get_ostr_cstr); #endif ASN1R_TAG_ADD (aCtx, CTX,10,get_vstr_prim); ASN1R_TAG_ADD (aCtx, CTX,11,get_gtime_prim); ASN1R_TAG_ADD (aCtx, CTX,12,get_btime_prim); ASN1R_TAG_ADD (aCtx, CTX,13,get_bcd_prim); ASN1R_TAG_ADD (aCtx, CTX,17,get_utc_time_prim); ASN1R_TAG_ADD (aCtx, CTX,RT_UTF8_STRING,get_utf8_prim); } } /************************************************************************/ /* init_new_RT */ /* This is the function called to check to see if a new RT table entry */ /* is required and available, and initializes it if so. */ /* Parameters: */ /* tag Tag value for the field type. */ /* el_len Element length, in its own units. 0 for constructed */ /* types. Units are bytes except for bitstrings (length */ /* given in bits). */ /* Globals input: */ /* cur_rt, nxt_un_rt, rt_EOB_ptr */ /* Globals output: */ /* nxt_un_rt */ /* Returns: */ /* 0 if OK, 1 if error (table overflow). */ /************************************************************************/ static int init_new_RT (ASN1_DEC_CTXT *aCtx, ST_UCHAR tag, ST_INT el_len) { ST_BOOLEAN prim; ST_INT st_size; prim = SD_TRUE; switch (tag) /* Calc storage size based on element fundamentals */ { case RT_BOOL: /* Size must be 1, so ignore it. */ st_size = 1; break; case RT_BIT_STRING: /* el_len was converted to bits */ st_size = CALC_BIT_LEN (el_len); /* Calculate byte count. */ break; case RT_INTEGER: /* Size is in bytes. */ case RT_UNSIGNED: st_size = el_len; /* already conditioned (1,2,4) */ break; case RT_BCD: /* always put into ST_INT32 */ st_size = 4; el_len = 8; /* assume type is 8 BCD digits */ break; case RT_FLOATING_POINT: /* Decrement el_len because it's used for storage size later */ st_size = (--el_len == 4) ? sizeof (float) : sizeof (double); break; case RT_OCTET_STRING: /* Size is in bytes. */ st_size = el_len; /* No terminating null */ break; /* If variable length, size will */ /* be increased by sizeof (ST_INT16) */ case RT_VISIBLE_STRING: /* Size is in bytes. */ st_size = el_len+1; /* Add space for terminating null */ break; /* No increase for variable length */ case RT_GENERAL_TIME: /* Generalized time */ st_size = sizeof (time_t); el_len = sizeof (time_t); break; case RT_BINARY_TIME: /* Binary time */ if (el_len == 6) st_size = 2 * sizeof (ST_INT32); else st_size = sizeof (ST_INT32); break; case RT_UTC_TIME: /* UTC time */ st_size = sizeof (MMS_UTC_TIME); /* 3 * sizeof (ST_UINT32); */ break; case RT_UTF8_STRING: /* Unicode UTF8string */ #if (UNICODE_LOCAL_FORMAT==UNICODE_UTF8) st_size = abs(el_len)*4 + 1; /* # bytes (4 bytes per char + NULL)*/ #else /* assume UNICODE_UTF16 */ st_size = abs(el_len)*2 + 2; /* # bytes (2 bytes per char + 2 byte NULL)*/ #endif break; default: prim = SD_FALSE; /* Not a primitive element. */ st_size = 0; break; } if (cur_rt == nxt_un_rt) /* If this element is not already defined, */ { /* We need to use another el, do ovrfl check */ if (nxt_un_rt == rt_EOB_ptr) /* Check against EOB pointer. */ { asn1r_set_dec_err (aCtx, MX_MEMORY_ALLOC); /* Table is full, declare error & return */ MLOG_ERR1 ("Exceeded %d limit on number of elements in RUNTIME_TYPE array", rt_EOB_ptr - rt_base); return SD_FAILURE; /* Error value. */ } ++nxt_un_rt; /* Used one more element. */ /* Clear the new element. */ memset ((char *)cur_rt, 0, sizeof (RUNTIME_TYPE)); cur_rt->el_tag = tag; /* Set the tag value. */ cur_rt->el_size = st_size; /* Set storage size */ if (prim) { if (tag == RT_BCD) cur_rt->u.p.el_len = 8; else cur_rt->u.p.el_len = el_len; /* Set initial data size for prim */ } if (tag == RT_ARR_START) cur_rt->u.arr.num_rt_blks = -1; /* Flag unfinished constructor */ else if (tag == RT_STR_START) cur_rt->u.str.num_rt_blks = -1; /* Flag unfinished constructor */ return SD_SUCCESS; /* New element, done. */ } /* The following code executes if this is an element of an array. */ /* It adjusts sizes if necessary. For example, if the second Vstring */ /* in an array is longer than the first, the el_len and el_size are */ /* increased to handle it. */ /* This is an "old" element. Check data sizes */ /* and update as required. Check for variable */ switch (tag) /* length issues in byte and bit strings. */ { case RT_BIT_STRING: /* Size is in bits */ if (cur_rt->u.p.el_len < 0) /* Is variable */ { /* Re-size if necessary */ if (-cur_rt->u.p.el_len < el_len) /* New one is bigger */ { cur_rt->u.p.el_len = -el_len; /* Set new length */ cur_rt->el_size = st_size + sizeof (ST_INT16); } } else if (cur_rt->u.p.el_len != el_len) /* Different length */ { /* Make variable length */ if (cur_rt->u.p.el_len > el_len) /* Size for biggest seen */ el_len = cur_rt->u.p.el_len; cur_rt->u.p.el_len = -el_len; cur_rt->el_size = CALC_BIT_LEN (el_len) + sizeof (ST_INT16); } break; case RT_INTEGER: /* Size is in bytes. */ case RT_UNSIGNED: if (st_size > cur_rt->el_size) /* If this one is bigger, */ { /* set both storage size */ cur_rt->el_size = /* and element length. */ cur_rt->u.p.el_len = st_size; } break; case RT_OCTET_STRING: /* Size is in bytes. */ if (cur_rt->u.p.el_len < 0) /* Variable size */ { if (-cur_rt->u.p.el_len < el_len) /* New one is longer */ { cur_rt->u.p.el_len = -el_len; /* Bump size up */ cur_rt->el_size = el_len + sizeof (ST_INT16); } } else if (cur_rt->u.p.el_len != el_len) /* Different size */ { if (-cur_rt->u.p.el_len > el_len) /* If old is bigger, */ el_len = -cur_rt->u.p.el_len; /* keep it, otherwise */ cur_rt->u.p.el_len = -el_len; /* use this size. */ cur_rt->el_size = el_len + sizeof (ST_INT16); } break; case RT_VISIBLE_STRING: /* Size is in bytes. */ if (cur_rt->u.p.el_len < 0) /* Variable len */ { if (cur_rt->u.p.el_len > -el_len) /* New one is bigger. */ cur_rt->u.p.el_len = -el_len; } else if (cur_rt->u.p.el_len != el_len) /* Length different */ { /* Make variable length */ if (cur_rt->u.p.el_len > el_len) el_len = cur_rt->u.p.el_len; cur_rt->u.p.el_len = -el_len; } cur_rt->el_size = abs (cur_rt->u.p.el_len) + 1; break; case RT_UTF8_STRING: /* Unicode UTF8string */ /* If new len > old len, force string to be "variable-len" & increase len.*/ if (abs(el_len) > abs(cur_rt->u.p.el_len)) /* New one is bigger. */ { cur_rt->u.p.el_len = -abs(el_len); /* increase len */ /* adjust el_size */ #if (UNICODE_LOCAL_FORMAT==UNICODE_UTF8) cur_rt->el_size = abs(cur_rt->u.p.el_len)*4 + 1; /* # bytes (4 bytes per char + NULL)*/ #else /* assume UNICODE_UTF16 */ cur_rt->el_size = abs(cur_rt->u.p.el_len)*2 + 2; /* # bytes (2 bytes per char + 2 byte NULL)*/ #endif } break; default: /* Other types are fixed length */ break; } return SD_SUCCESS; /* All OK. */ } /************************************************************************/ /* next_rt_index */ /* Sets cur_rt to the correct value for the next data element in */ /* the parse. If the current message level is an unfinished array, */ /* it increments the u.arr.num_elmnts member of the header. */ /* Parameters: None. */ /* Globals input: cur_rt, nxt_un_rt, constr_type[] */ /* Globals output: cur_rt */ /* Other variables changed: cur_rt->u.arr.num_elmnts */ /************************************************************************/ static ST_VOID next_rt_index (ASN1_DEC_CTXT *aCtx) { if (++cur_rt < nxt_un_rt) /* Next RT element already defined? */ return; /* Return, done. */ /* The current message level isn't complete yet. Check type. */ if (constr_type[aCtx->asn1r_msg_level] == ARRAY) /* This is an unfinished array. */ { cur_rt = rt_blk_start[aCtx->asn1r_msg_level]; /* Loop back to array start */ cur_rt->u.arr.num_elmnts++; /* Inc # of elements. */ ++cur_rt; /* Point to contents. */ } /* Done. No loopback is required for structures, only arrays. */ } /************************************************************************/ /* arr_start */ /* This is the function called when an array cstr is starting */ /************************************************************************/ static ST_VOID arr_start (ASN1_DEC_CTXT *aCtx) { /* initialize the loop counter for the array */ MLOG_CDEC0 ("pars_arr_start"); if (init_new_RT (aCtx, RT_ARR_START, 0)) /* Return if error. */ return; /* Check to see if the end-contructor for this array */ /* has been encountered before. */ ++arr_loop_level; if (cur_rt->u.arr.num_rt_blks == -1) { aCtx->asn1r_c_done_fun[aCtx->asn1r_msg_level] = arr_done_fun; /* Init now if new array */ } else /* We've seen this array before as an element of a larger array. We */ /* know the size. Initialize the loop count in the RT_ARR_END block. */ { arr_loops[arr_loop_level] = cur_rt->u.arr.num_elmnts; } rt_blk_start[aCtx->asn1r_msg_level] = cur_rt; /* Point to initial element */ constr_type[aCtx->asn1r_msg_level] = ARRAY; cur_rt++; /* Increment index (no loopback) */ assign_tags (aCtx); /* Assign tags for next data element. */ } /************************************************************************/ /* arr_done_fun */ /* This is the cstr done function called when an array cstr is done */ /* Note: aCtx->asn1r_msg_level is one less than the value given to array_start (). */ /************************************************************************/ static ST_VOID arr_done_fun (ASN1_DEC_CTXT *aCtx) { MLOG_CDEC0 ("pars_arr_done_fun"); if (rt_blk_start[aCtx->asn1r_msg_level+1]->u.arr.num_rt_blks == -1) { /* Unfinished array, build RT_ARR_END record. */ cur_rt = nxt_un_rt; /* Point to one past end */ if (init_new_RT (aCtx, RT_ARR_END, 0)) /* Init a new RT block */ return; cur_rt->u.arr.num_rt_blks = /* Calc RT block count for array. */ rt_blk_start[aCtx->asn1r_msg_level+1]->u.arr.num_rt_blks = (cur_rt - rt_blk_start[aCtx->asn1r_msg_level+1] - 1);/* Copy count back to start. */ cur_rt->u.arr.num_elmnts = /* Copy element count to */ rt_blk_start[aCtx->asn1r_msg_level+1]->u.arr.num_elmnts;/* end-array element.*/ } else { /* This is the end of a finished array. */ if (arr_loops[arr_loop_level]) /* Loop count down to 0? */ { MLOG_NERR0 ("Malformed array data"); asn1r_set_dec_err (aCtx, BAD_DATA); /* If not exactly 0, error. */ } } --arr_loop_level; next_rt_index (aCtx); assign_tags (aCtx); /* setup to get next element */ } /************************************************************************/ /* str_start */ /* This is the function called when a struct cstr is starting */ /************************************************************************/ static ST_VOID str_start (ASN1_DEC_CTXT *aCtx) { if (init_new_RT (aCtx, RT_STR_START, 0)) return; if (cur_rt->u.str.num_rt_blks == -1) aCtx->asn1r_c_done_fun[aCtx->asn1r_msg_level] = str_done_fun; /* Init now if new struct */ rt_blk_start[aCtx->asn1r_msg_level] = cur_rt; /* Point to initial element */ constr_type[aCtx->asn1r_msg_level] = STRUCT; cur_rt++; /* point to next runtime element always */ assign_tags (aCtx); /* setup to get next element */ } /************************************************************************/ /* str_done_fun */ /* This is the cstr done function called when a struct cstr is done */ /* Note: aCtx->asn1r_msg_level is one less than the value given to str_start (). */ /************************************************************************/ static ST_VOID str_done_fun (ASN1_DEC_CTXT *aCtx) { MLOG_CDEC0 ("pars_str_done_fun"); if (init_new_RT (aCtx, RT_STR_END, 0)) return; cur_rt->u.str.num_rt_blks = /* Calc RT block count for struct. */ rt_blk_start[aCtx->asn1r_msg_level+1]->u.str.num_rt_blks = (cur_rt - rt_blk_start[aCtx->asn1r_msg_level+1] - 1); /* Copy count back to start. */ next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); /* setup to get next element */ } /************************************************************************/ /************************************************************************/ #if 0 /* Constructed bitstrings and octetstrings not supported */ /************************************************************************/ /************************************************************************/ /* get_bstr_cstr */ /* State function to extract a boolean value from an asn1 data element. */ /************************************************************************/ static ST_VOID get_bstr_cstr (ASN1_DEC_CTXT *aCtx) &&& This code not implemented. { MLOG_CDEC0 ("pars_get_bstr_cstr"); if (init_new_RT (aCtx, RT_STR_END, 0)) return; aCtx->asn1r_c_done_fun [aCtx->asn1r_msg_level] = bs_cstr_done; next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); /* setup to get next element */ } /************************************************************************/ /* bs_cstr_done */ /* This function is called when an bit string constructor is */ /* completed OK. Need to reset the decode state machine. */ /* Note: aCtx->asn1r_msg_level is one less than the value given to get_bstr_cstr (). */ /************************************************************************/ static ST_VOID bs_cstr_done (ASN1_DEC_CTXT *aCtx) &&& Not implemented yet { ST_INT abs_len; ST_INT abs_count; int i; ST_CHAR *to_ptr; ST_CHAR *from_ptr; abs_count = abs (cur_rt->u.p.el_len); abs_len = CALC_BIT_LEN (abs_count); /* determine whether octet string is fixed or variable length */ if (cur_rt->u.p.el_len >=0) /* fixed length */ { if (aCtx->asn1r_bitcount != abs_count) { MLOG_NERR0 ("Fixed length bit string mismatch"); asn1r_set_dec_err (aCtx, BAD_DATA); } } else /* variable length bit string */ { /* need to move down to allow for size ST_INT16 */ from_ptr = datptr+abs_len-1; to_ptr = from_ptr+sizeof (ST_INT16); for (i = 0; i < abs_count; ++i) *(to_ptr--) = *(from_ptr--); *((ST_INT16 *)datptr) = (ST_INT16) aCtx->asn1r_bitcount; } datptr += cur_rt->el_size; /* Adjust data pointer */ cur_rt++; /* point to next runtime element */ assign_tags (aCtx); /* Assign tags for next data elt*/ } /************************************************************************/ /* get_ostr_cstr */ /* State function to extract an octet string from an asn1 data element. */ /************************************************************************/ static ST_VOID get_ostr_cstr (ASN1_DEC_CTXT *aCtx) { MLOG_CDEC0 ("pars_get_ostr_cstr"); aCtx->asn1r_c_done_fun [aCtx->asn1r_msg_level] = os_cstr_done; asn1r_get_octstr_cstr (aCtx, abs (cur_rt->u.p.el_len), datptr); } /************************************************************************/ /* os_cstr_done */ /* This function is called when an octet string constructor is */ /* completed OK. Need to reset the decode state machine. */ /************************************************************************/ static ST_VOID os_cstr_done (ASN1_DEC_CTXT *aCtx) { ST_INT abs_len; int i; ST_CHAR *to_ptr; ST_CHAR *from_ptr; abs_len = abs (cur_rt->u.p.el_len); /* determine whether octect string is fixed or variable length */ if (cur_rt->u.p.el_len >=0) /* fixed length */ { if (aCtx->asn1r_octetcount != abs_len) { MLOG_NERR0 ("Fixed length octet string mismatch"); asn1r_set_dec_err (aCtx, BAD_DATA); } } else /* variable length octet string */ { /* need to move down to allow for size ST_INT16 */ from_ptr = datptr+abs_len-1; to_ptr = from_ptr+sizeof (ST_INT16); for (i = 0; i < aCtx->asn1r_octetcount; ++i) *(to_ptr--) = *(from_ptr--); *((ST_INT16 *)datptr) = (ST_INT16) aCtx->asn1r_octetcount; } datptr += cur_rt->el_size; /* Adjust data pointer */ cur_rt++; /* point to next runtime element */ assign_tags (aCtx); /* Assign tags for next data elt*/ } /************************************************************************/ #endif /************************************************************************/ /************************************************************************/ /************************************************************************/ /* get_bool_prim */ /* State function to extract a boolean prim from an asn1 data element. */ /************************************************************************/ static ST_VOID get_bool_prim (ASN1_DEC_CTXT *aCtx) { MLOG_CDEC0 ("pars_get_bool_prim"); if (init_new_RT (aCtx, RT_BOOL, aCtx->asn1r_elmnt_len)) return; if (aCtx->asn1r_elmnt_len != 1) { MLOG_NERR0 ("Malformed boolean data"); asn1r_set_dec_err (aCtx, BAD_DATA); /* checked by get function */ } aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len; /* Skip over data */ next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); /* setup to get next element */ } /************************************************************************/ /* get_bitstr_prim */ /* State function to extract a bitstring prim from an asn1 data element */ /************************************************************************/ static ST_VOID get_bitstr_prim (ASN1_DEC_CTXT *aCtx) { ST_INT bit_count; MLOG_CDEC0 ("pars_get_bitstr_prim"); bit_count = (aCtx->asn1r_elmnt_len > 1) ? ((aCtx->asn1r_elmnt_len-1)*8 - (*aCtx->asn1r_field_ptr & 7)) : 0; if (!aCtx->asn1r_elmnt_len || (!bit_count && *aCtx->asn1r_field_ptr)) { MLOG_NERR0 ("Malformed bitstring data"); asn1r_set_dec_err (aCtx, BAD_DATA); } if (init_new_RT (aCtx, RT_BIT_STRING, bit_count)) return; aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len; next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); } /************************************************************************/ /* get_int_prim */ /* State function to extract an integer prim from an asn1 data element. */ /************************************************************************/ static ST_VOID get_int_prim (ASN1_DEC_CTXT *aCtx) { ST_INT el_len; MLOG_CDEC0 ("pars_get_int_prim"); switch (aCtx->asn1r_elmnt_len) /* determine internal length */ { case 1: /* one byte int */ el_len = 1; break; case 2: /* two byte int */ el_len = 2; break; case 3: /* three byte int, expand to 4 */ case 4: /* four byte integer */ el_len = 4; break; #ifdef INT64_SUPPORT case 5: case 6: case 7: case 8: el_len = 8; break; #endif default : MLOG_NERR0 ("Malformed integer data"); asn1r_set_dec_err (aCtx, BAD_DATA); /* no other lengths are valid */ return; } /* Assume all integers at least 4 bytes (i.e. ST_INT32). */ if (el_len < 4) el_len = 4; if (init_new_RT (aCtx, RT_INTEGER, el_len)) return; aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len; next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); } /************************************************************************/ /* get_uint_prim */ /* State function to extract an unsigned integer prim from an asn1 data */ /* element. */ /************************************************************************/ static ST_VOID get_uint_prim (ASN1_DEC_CTXT *aCtx) { ST_INT el_len; ST_INT asn1ElmntLen; MLOG_CDEC0 ("pars_get_uint_prim"); /* Unsigned data may have a leading 0x00 if it otherwise would be neg */ asn1ElmntLen = aCtx->asn1r_elmnt_len; if (aCtx->asn1r_elmnt_len > 1 && *aCtx->asn1r_field_ptr == 0 && *(aCtx->asn1r_field_ptr+1) & 0x80) { --asn1ElmntLen; } switch (asn1ElmntLen) /* determine internal length */ { case 1: /* one byte */ el_len = 1; break; case 2: /* two bytes */ el_len = 2; break; case 3: /* three bytes, expand to 4 */ case 4: /* four bytes */ el_len = 4; break; #ifdef INT64_SUPPORT case 5: case 6: case 7: case 8: el_len = 8; break; #endif default : MLOG_NERR0 ("Malformed unsigned data"); asn1r_set_dec_err (aCtx, BAD_DATA); /* no other lengths are valid */ return; } /* Assume all unsigned integers at least 4 bytes (i.e. ST_UINT32). */ if (el_len < 4) el_len = 4; if (init_new_RT (aCtx, RT_UNSIGNED, el_len)) return; aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len; next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); } /************************************************************************/ /* get_float_prim */ /* State function to extract a floating point primitive from an asn1 */ /* data element. */ /************************************************************************/ #ifdef FLOAT_DATA_SUPPORT static ST_VOID get_float_prim (ASN1_DEC_CTXT *aCtx) { MLOG_CDEC0 ("pars_get_float_prim"); if (init_new_RT (aCtx, RT_FLOATING_POINT, aCtx->asn1r_elmnt_len)) return; aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len; next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); } #endif /************************************************************************/ /* get_octstr_prim */ /* State function to extract an octet string primitive from an asn1 */ /* data element. */ /************************************************************************/ static ST_VOID get_octstr_prim (ASN1_DEC_CTXT *aCtx) { MLOG_CDEC0 ("pars_get_octstr_prim"); if (init_new_RT (aCtx, RT_OCTET_STRING, aCtx->asn1r_elmnt_len)) return; aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len; next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); } /************************************************************************/ /* get_vstr_prim */ /* State function to extract a visible string primitive from an asn1 */ /* data element. */ /************************************************************************/ static ST_VOID get_vstr_prim (ASN1_DEC_CTXT *aCtx) { MLOG_CDEC0 ("pars_get_vstr_prim"); if (init_new_RT (aCtx, RT_VISIBLE_STRING, aCtx->asn1r_elmnt_len)) return; aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len; next_rt_index (aCtx); /* point to next runtime element*/ assign_tags (aCtx); } /************************************************************************/ /* get_gtime_prim */ /* State function to extract a generalized time primitive from an asn1 */ /* data element. */ /************************************************************************/ #ifdef TIME_DATA_SUPPORT static ST_VOID get_gtime_prim (ASN1_DEC_CTXT *aCtx) { MLOG_CDEC0 ("pars_get_gtime_prim"); if (init_new_RT (aCtx, RT_GENERAL_TIME, aCtx->asn1r_elmnt_len)) return; aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len; next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); } #endif /************************************************************************/ /* get_btime_prim */ /* State function to extract a binary time primitive from an asn1 data */ /* element. */ /************************************************************************/ #ifdef BTOD_DATA_SUPPORT static ST_VOID get_btime_prim (ASN1_DEC_CTXT *aCtx) { MLOG_CDEC0 ("pars_get_btime_prim"); if (init_new_RT (aCtx, RT_BINARY_TIME, aCtx->asn1r_elmnt_len)) return; aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len; next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); } #endif /************************************************************************/ /* get_bcd_prim */ /* State function to extract a binary coded decimal primitive from an */ /* asn1 data element. */ /************************************************************************/ static ST_VOID get_bcd_prim (ASN1_DEC_CTXT *aCtx) { MLOG_CDEC0 ("pars_get_bcd_prim"); if (aCtx->asn1r_elmnt_len > 4) { MLOG_NERR0 ("Malformed bcd data"); asn1r_set_dec_err (aCtx, BAD_DATA); return; } if (init_new_RT (aCtx, RT_BCD, aCtx->asn1r_elmnt_len)) return; aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len; /* Adjust data pointer */ next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); } /************************************************************************/ /* get_utc_time_prim */ /* State function to extract a utc time primitive from an asn1 data */ /* element. */ /************************************************************************/ static ST_VOID get_utc_time_prim (ASN1_DEC_CTXT *aCtx) { MLOG_CDEC0 ("pars_get_utc_time_prim"); if (init_new_RT (aCtx, RT_UTC_TIME, aCtx->asn1r_elmnt_len)) return; aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len; next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); } /************************************************************************/ /* get_utf8_prim */ /* State function to extract a Unicode UTF8string primitive from an */ /* asn1 data element. */ /* Assume string is "variable-length", so pass "negative" len. The len */ /* is the number of Unicode characters. Each Unicode character takes */ /* at least 1 byte, so the number of characters is ALWAYS <= */ /* the ASN.1 encoded size. */ /************************************************************************/ static ST_VOID get_utf8_prim (ASN1_DEC_CTXT *aCtx) { MLOG_CDEC0 ("get_utf8_prim"); /* Pass "negative" len to indicate "variable-length". */ if (init_new_RT (aCtx, RT_UTF8_STRING, -aCtx->asn1r_elmnt_len)) return; aCtx->asn1r_field_ptr += aCtx->asn1r_elmnt_len; next_rt_index (aCtx); /* point to next runtime element */ assign_tags (aCtx); } /************************************************************************/ /* err_clean_fun */ /************************************************************************/ static ST_VOID err_clean_fun (ASN1_DEC_CTXT *aCtx, ST_RET err_code) { if (local_alloc_flag) { chk_free (rt_base); rt_base = NULL; } nxt_un_rt = rt_base; /* Zero length runtime buffer. */ }