/* * Copyright (C) 1997-1998 by Objective Systems, Inc. * * This software is furnished under a license and may be used and copied * only in accordance with the terms of such license and with the * inclusion of the above copyright notice. This software or any other * copies thereof may not be provided or otherwise made available to any * other person. No title to and ownership of the software is hereby * transferred. * * The information in this software is subject to change without notice * and should not be construed as a commitment by Objective Systems, Inc. * * PROPRIETARY NOTICE * * This software is an unpublished work subject to a confidentiality agreement * and is protected by copyright and trade secret law. Unauthorized copying, * redistribution or other use of this work is prohibited. * * The above notice of copyright on this source code product does not indicate * any actual or intended publication of such source code. * *****************************************************************************/ /*********************************************************************** /* /* File name : xdecode.cc /* /* Module name : xdecode /* /* Description : This module is responsible for decoding each /* of the primitive ASN message types into an /* equivalent C variable. The primitive ASN /* message types include boolean, integer, bit /* string, byte string, null, real, object /* identifier, and enumerated. /* /* Callable Routines : xd_setp /* xd_tag_len /* xd_tag /* xd_len /* xd_match /* xd_boolean /* xd_integer /* xd_bitstr /* xd_octstr /* xd_enum /* xd_null /* xd_objid /* xd_any /* xd_push /* xd_chkend /* xd_count /* /***********************************************************************/ #include #include #include #include #include #include "asn1type.h" /*********************************************************************** /* /* Routine name: xd_tag /* /* Description: This routine decodes an ASN tag into a standard 16 bit /* structure. This structure represents a tag as follows: /* /* Bit#: 11 1 1110000000000 /* 54 3 2109876543210 /* |__|_|_____________| /* ^ ^ ID code /* | | /* | +- Form: /* | 0 = Primitive, /* | 1 = Constructor /* | /* +---- Class: /* 0 (00) = Universal /* 1 (01) = Application /* 2 (10) = Context-specific /* 3 (11) = Private /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* ctxt_p struct Pointer to ASN.1 context block structure /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status of operation. Returned as function result. /* tag struct Structure containing class, form, and id_code. /* /***********************************************************************/ int xd_tag (ASN1CTXT* ctxt_p, ASN1TAG *tag_p) { ASN1OCTET b; ASN1USINT class_form, id_code; register stat; *tag_p = 0; if ((stat = xd_memcpy (ctxt_p, &b, 1)) == ASN_OK) { class_form = (b & TM_CLASS_FORM) * 256; if ((id_code = b & TM_B_IDCODE) == 31) { id_code = 0; do { if ((stat = xd_memcpy (ctxt_p, &b, 1)) == ASN_OK) { id_code = (id_code * 128) + (b & 0x7F); if (id_code > 0x1FFF) return (ASN_E_BADTAG); } else break; } while (b & 0x80); } *tag_p = class_form | id_code; } return (stat); } /*********************************************************************** /* /* Routine name: xd_tag_len /* /* Description: This routine parses the X.409 ID and length fields /* located at the current message pointer position and /* advances the message pointer to the start of the /* contents field. /* /* The routine first saves the current message pointer /* and length values on local variables. It then takes /* the byte located at the message pointer and parses it /* according to the X.409 rules to get the class, form, /* and ID values. The internal routine xd_len is then /* called to parse the length value. /* /* xd_tag_len monitors indefinite length messages as /* follows: Each time a length is parsed, it is checked /* to see if it is an indefinite length value. If it is, /* an indefinite length section counter is incremented. /* Each time an end-of-contents (EOC) identifier is /* parsed, this counter is decremented. When the counter /* goes to zero, end of message is signalled. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* ctxt_p struct Pointer to ASN.1 context block structure /* flags byte Bit flags used to set the following options: /* XM_ADVANCE: Advance decode pointer on match. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status of operation. Returned as function result /* tag_p ushort Structure containing class, form, and id_code /* len_p int Length of message component. Returned as follows: /* >= 0 component is fixed length /* ASN_K_INDEFLEN component is indefinite length /* /***********************************************************************/ int xd_tag_len (ASN1CTXT *ctxt_p, ASN1TAG *tag_p, int *len_p, ASN1OCTET flags) { register stat; /* Save context prior to parsing this tag and length. It may be */ /* by generated decode functions to restore the decode point if */ /* an operation is to be retried.. */ ASN1BUF_SAVE (ctxt_p); if ((stat = xd_tag (ctxt_p, tag_p)) == ASN_OK) { stat = xd_len (ctxt_p, len_p); /* Indefinite length message check.. if indefinite length parsed, */ /* bump indefinite length section counter; if EOC ID parsed, */ /* decrement count. If overall message is of indefinite length */ /* and count goes to zero, signal end of message. */ if (stat == ASN_OK) { if (*len_p == ASN_K_INDEFLEN) ctxt_p->buf.ilcnt++; else if (*tag_p == 0 && *len_p == 0) ctxt_p->buf.ilcnt--; if (ctxt_p->buf.rembytes == ASN_K_INDEFLEN && ctxt_p->buf.ilcnt == 0) stat = ASN_E_ENDOFBUF; } } if (!(flags & XM_ADVANCE)) ASN1BUF_RESTORE (ctxt_p); return (stat); } /*********************************************************************** /* /* Routine name: xd_match /* /* Description: This routine compares the X.409 ID field located at /* the current message pointer position with the given /* class and ID value. If a match occurs, the length /* field is decoded and the length is returned to the /* caller. If the input parameter 'advance' is set to /* TRUE, the message pointer is advanced to the beginning /* of the contents field. A subsequent X.409 decode call /* can then be used to decode the data. /* /* If a match does not occur, the routine will skip to /* subsequent fields in search of a match. If a match /* is eventually found, the processing described above /* is done; otherwise, a not found status is returned to /* the caller. /* /* The routine first takes the byte located at the message /* pointer and parses it according to the X.409 rules to /* get the class, form, and ID values. It then compares /* these values with the given values. If a match occurs, /* the internal routine xd_len is called to parse the /* length value. This value is returned to the caller /* and the message pointer is advanced to point to the /* start of the data field. /* /* If the match operation fails, the message pointer is /* advanced to the next field by adding the parsed length /* value to the pointer. The comparison is then attempted /* again. This is repeated until either a match occurs or /* the end of the message is encountered. If end of message /* is encountered, the message pointer is returned to its /* original location and a not found status is returned to /* the caller. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* ctxt_p struct Pointer to ASN.1 context block structure /* tag ushort Tag to match /* flags byte Bit flags used to set the following options: /* XM_ADVANCE: Advance decode pointer on match. /* XM_SEEK : Seek until match found or EOM. /* XM_SKIP : Skip to next tag before search /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status of operation. Returned as function result. /* length int Length of message component. Returned as follows: /* >= 0 component is fixed length /* ASN_K_INDEFLEN component is indefinite length /* /***********************************************************************/ int xd_match (ASN1CTXT *ctxt_p, ASN1TAG tag, int *len_p, ASN1OCTET flags) { ASN1BUF saved_ctxt; int parsed_len; ASN1TAG parsed_tag; char buf[8]; register found = FALSE, status = ASN_OK; /* If skip flag set, advance decode pointer to next field */ if (flags & XM_SKIP) { status = xd_tag_len (ctxt_p, &parsed_tag, &parsed_len, XM_ADVANCE); if (status == ASN_OK) { if (!(parsed_tag & TM_CONS)) { ctxt_p->buf.ptr += parsed_len; /* advance decode pointer */ if (ctxt_p->buf.rembytes != ASN_K_INDEFLEN) ctxt_p->buf.rembytes -= parsed_len; } } else if (status == ASN_E_ENDOFBUF) { xu_addTagErrParm (ctxt_p, tag); /* expected tag */ xu_addTagErrParm (ctxt_p, parsed_tag); /* parsed tag */ return (ASN_E_IDNOTFOU); } else return (status); } /* Save the context here in the event a seek is to be performed. */ /* If element being seeked is not found, this will be need to */ /* return to the original starting point.. */ memcpy (&saved_ctxt, &ctxt_p->buf, sizeof(ASN1BUF)); do { status = xd_tag_len (ctxt_p, &parsed_tag, &parsed_len, XM_ADVANCE); if (status == ASN_OK) { if (tag == parsed_tag) { found = TRUE; if (len_p) *len_p = parsed_len; if (!(flags & XM_ADVANCE)) ASN1BUF_RESTORE (ctxt_p); } else if ((flags & XM_SEEK) && (!(parsed_tag & TM_CONS))) { ctxt_p->buf.ptr += parsed_len; /* advance decode pointer */ if (ctxt_p->buf.rembytes != ASN_K_INDEFLEN) ctxt_p->buf.rembytes -= parsed_len; } } } while (!found && (flags & XM_SEEK) && status == ASN_OK); if (!found) { memcpy (&ctxt_p->buf, &saved_ctxt, sizeof(ASN1BUF)); if (status == ASN_E_ENDOFBUF || status == ASN_OK) { xu_addTagErrParm (ctxt_p, tag); /* expected tag */ xu_addTagErrParm (ctxt_p, parsed_tag); /* parsed tag */ status = ASN_E_IDNOTFOU; } } return (status); } /*********************************************************************** /* /* Routine name: xd_boolean /* /* Description: This routine decodes the boolean value at the current /* message pointer location and returns the value. It /* also advances the message pointer to the start of the /* the next field. /* /* The routine first checks to see if explicit tagging /* is specified. If yes, it calls xd_match to match /* the universal tag for this message type. If the /* match is not successful, a negative value is returned /* to indicate the parse was not successful. /* /* If the match is successful or implicit tagging is /* specified, xd_memcpy is called to fetch the data value. /* This routine will take into account length to ensure /* the data is properly retrieved. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* ctxt_p struct Pointer to ASN.1 context block structure /* tagging enum Specifies whether element is implicitly or /* explicitly tagged. /* length int Length of data to retrieve. Valid for implicit /* case only. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status of operation. Returned as function result. /* object bool Decoded boolean data value. /* /***********************************************************************/ int xd_boolean (ASN1CTXT *ctxt_p, ASN1BOOL *object_p, ASN1TagType tagging, int length) { register status = ASN_OK; if (tagging == ASN1EXPL) status = xd_match (ctxt_p, TM_UNIV|TM_PRIM|ASN_ID_BOOL, &length, XM_ADVANCE); if (status == ASN_OK) status = xd_memcpy (ctxt_p, object_p, length); return (status); } /*********************************************************************** /* /* Routine name: xd_integer /* /* Description: This routine decodes the integer value at the current /* message pointer location and returns the value. It /* also advances the message pointer to the start of the /* the next field. /* /* The routine first checks to see if explicit tagging /* is specified. If yes, it calls xd_match to match /* the universal tag for this message type. If the /* match is not successful, a negative value is returned /* to indicate the parse was not successful. /* /* If the match is successful or implicit tagging is /* specified, xd_memcpy is called to fetch the /* data value. This routine will take into account /* the overall message length to ensure the data is /* properly retrieved. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* ctxt_p struct Pointer to ASN.1 context block structure /* tagging enum Specifies whether element is implicitly or /* explicitly tagged. /* length int Length of data to retrieve. Valid for implicit /* case only. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status of operation. Returned as function result. /* object int Decoded integer data value. /* /**********************************************************************/ int xd_integer (ASN1CTXT *ctxt_p, ASN1INT *object_p, ASN1TagType tagging, int length) { register status = ASN_OK; char b; /* signed */ ASN1OCTET ub; /* unsigned */ if (tagging == ASN1EXPL) status = xd_match (ctxt_p, TM_UNIV|TM_PRIM|ASN_ID_INT, &length, XM_ADVANCE); if (status == ASN_OK) { /* Copy first byte into a signed char variable and assign it to */ /* object. This should handle sign extension in the case of a */ /* negative number.. */ if (length > 0) if ((status = xd_memcpy (ctxt_p, (ASN1OCTET *)&b, 1)) == ASN_OK) { *object_p = b; length--; } /* Now use unsigned bytes to add in the rest of the integer.. */ while (length > 0 && status == ASN_OK) if ((status = xd_memcpy (ctxt_p, &ub, 1)) == ASN_OK) { *object_p = (*object_p * 256) + ub; length--; } } return (status); } /*********************************************************************** /* /* Routine name: xd_bitstr_s (decode static bit string) /* /* Description: This routine decodes the bit string at the current /* message pointer location and returns its value. The /* value is returned in the "ASNBITSTR" structure. This /* structure contains a value for the number of bits and /* a pointer to the decoded bit string. The routine /* also advances the message pointer to the start of the /* the next field. /* /* The routine first checks to see if explicit tagging /* is specified. If yes, it calls xd_match to match /* the universal tag for this message type. If the /* match is not successful, a negative value is returned /* to indicate the parse was not successful. /* /* If the match is successful or implicit tagging is /* specified, the first byte of the data value is fetched. /* This byte contains a value indicating the number of bits /* in the last octet that are unused. Dynamic memory is /* then allocated for the bit string and xd_memcpy /* is called to copy the string from the message to the /* allocated memory. The number of bits is calculated by /* multiplying the number of octets times eight bits/octet /* and then subtracting the number of unused bits obtained /* above. The number of bits and dynamic memory pointer /* are passed back to the caller via the "ASNBITSTR" /* structure. The actual length of the string in bytes is /* returned as the function result. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* ctxt_p struct Pointer to ASN.1 context block structure /* tagging enum Specifies whether element is implicitly or /* explicitly tagged. /* length int Length of data to retrieve. Valid for implicit /* case only. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status of operation. Returned as function result. /* object char* Decoded bit string value. /* numbits int Number of bits in string. /* /**********************************************************************/ int xd_bitstr_s (ASN1CTXT *ctxt_p, ASN1OCTET *object_p, int *numbits_p, ASN1TagType tagging, int length) { register nbytes, status = ASN_OK; ASN1OCTET b; if (tagging == ASN1EXPL) status = xd_match (ctxt_p, TM_UNIV|TM_PRIM|ASN_ID_BITSTR, &length, XM_ADVANCE); if (status == ASN_OK) { if ((status = xd_memcpy (ctxt_p, &b, 1)) == ASN_OK) { if ((nbytes = (*numbits_p - 1) / 8 + 1) < length) { status = xd_memcpy (ctxt_p, object_p, length-1); *numbits_p = (nbytes * 8) - b; } else status = ASN_E_STROVFLW; } } return (status); } /*********************************************************************** /* /* Routine name: xd_bitstr /* /* Description: This routine decodes the bit string at the current /* message pointer location and returns its value. This /* routine is identical to the xd_bitstr_s above /* except for the fact that dynamic memory is allocated /* for the decoded string. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* ctxt_p struct Pointer to ASN.1 context block structure /* tagging enum Specifies whether element is implicitly or /* explicitly tagged. /* length int Length of data to retrieve. Valid for implicit /* case only. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status of operation. Returned as function result. /* object char** Pointer to decoded bit string value. /* numbits int Number of bits in string. /* /**********************************************************************/ int xd_bitstr (ASN1CTXT *ctxt_p, ASN1OCTET **object_p2, int *numbits_p, ASN1TagType tagging, int length) { register status = ASN_OK; if (tagging == ASN1EXPL) status = xd_match (ctxt_p, TM_UNIV|TM_PRIM|ASN_ID_BITSTR, &length, XM_ADVANCE); if (status == ASN_OK) { if (*object_p2 = (ASN1OCTET*) xu_malloc (ctxt_p, length - 1)) { *numbits_p = (length - 1) * 8; /* set max # bits */ status = xd_bitstr_s (ctxt_p, *object_p2, numbits_p, ASN1IMPL, length); } else status = ASN_E_NOMEM; } return (status); } /*********************************************************************** /* /* Routine name: xd_octstr_s (decode static octet string) /* /* Description: This routine decodes the octet string at the current /* message pointer location and returns its value. The /* value is returned in the buffer pointed to by the given /* character buffer pointer. This routine also advances /* the message pointer to the start of the next field. /* /* The routine first checks to see if explicit tagging /* is specified. If yes, it calls xd_match to match /* the universal tag for this message type. If the /* match is not successful, a negative value is returned /* to indicate the parse was not successful. /* /* If the match is successful or implicit tagging is /* specified, the string is copied into the static buffer /* using xd_memcpy. The numocts field is then set to the /* length parsed from the field. The status result of /* the operation is returned. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* ctxt_p struct Pointer to ASN.1 context block structure /* tagging enum Specifies whether element is implicitly or /* explicitly tagged. /* length int Length of data to retrieve. Valid for implicit /* case only. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status of operation. Returned as function result. /* object char* Pointer to decoded octet string value. /* numocts int Number of octets in string. /* /**********************************************************************/ int xd_octstr_s (ASN1CTXT *ctxt_p, ASN1OCTET *object_p, int *numocts_p, ASN1TagType tagging, int length) { register status = ASN_OK; if (tagging == ASN1EXPL) status = xd_match (ctxt_p, TM_UNIV|TM_PRIM|ASN_ID_OCTSTR, &length, XM_ADVANCE); if (status == ASN_OK) { if (length <= *numocts_p) { status = xd_memcpy (ctxt_p, object_p, length); *numocts_p = length; } else status = ASN_E_STROVFLW; } return (status); } /*********************************************************************** /* /* Routine name: xd_octstr /* /* Description: This routine decodes the octet string at the current /* message pointer location and returns its value. This /* routine is identical to the xd_octstr_s above /* except for the fact that dynamic memory is allocated /* for the decoded string. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* tagging bool Specifies whether element is implicitly or /* explicitly tagged. /* length int Length of data to retrieve. Valid for implicit /* case only. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status of operation. Returned as function result. /* object char** Pointer to decoded octet string value. /* numocts int Number of octets in string. /* /**********************************************************************/ int xd_octstr (ASN1CTXT *ctxt_p, ASN1OCTET **object_p2, int *numocts_p, ASN1TagType tagging, int length) { register status = ASN_OK; if (tagging == ASN1EXPL) status = xd_match (ctxt_p, TM_UNIV|TM_PRIM|ASN_ID_OCTSTR, &length, XM_ADVANCE); if (status == ASN_OK) { if (*object_p2 = (ASN1OCTET*) xu_malloc (ctxt_p, length)) { *numocts_p = length; status = xd_octstr_s (ctxt_p, *object_p2, numocts_p, ASN1IMPL, length); } else status = ASN_E_NOMEM; } return (status); } /*********************************************************************** /* /* Routine name: xd_null /* /* Description: This routine decodes the null value at the current /* message pointer location. Its main purpose is just to /* verify that an expected null placeholder is present, /* since the null identifier has no associated contents. /* /* The routine calls xd_match to match the universal /* tag for this message type. If the match is not /* successful, a not found status is returned to indicate /* the parse was not successful. /* /* If the match is successful, the message pointer is /* advance to the next field. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* tagging bool Specifies whether element is implicitly or /* explicitly tagged. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* status int Status of operation. Returned as function result. /* /***********************************************************************/ int xd_null (ASN1CTXT *ctxt_p, ASN1TagType tagging) { if (tagging == ASN1EXPL) return (xd_match (ctxt_p, TM_UNIV|TM_PRIM|ASN_ID_NULL, NULL, XM_ADVANCE)); else return (ASN_OK); } /*********************************************************************** /* /* Routine name: xd_objid /* /* Description: This routine decodes the object at the current /* message pointer location and returns its value. The /* value is returned in the "ASNOBJID" structure. This /* structure contains a value for the number of subident- /* and a pointer to an array of integers which contain the /* subidentifer values. /* /* The routine first checks to see if explicit tagging /* is specified. If yes, it calls xd_match to match /* the universal tag for this message type. If the /* match is not successful, a negative value is returned /* to indicate the parse was not successful. /* /* If the match is successful or implicit tagging is /* specified, the object identifer contents are decoded /* and stored on the "ASNOBJID" structure. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* tagging bool Specifies whether element is implicitly or /* explicitly tagged. /* length int Length of data to retrieve. Valid for implicit /* case only. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* status int Status of operation. Returned as function result. /* object struct Decoded object identifier value. /* length int Actual length of message component. /* /**********************************************************************/ int xd_objid (ASN1CTXT *ctxt_p, ASN1OBJID *object_p, ASN1TagType tagging, int length) { int status, j; unsigned subid; ASN1OCTET b; status = ASN_OK; if (tagging == ASN1EXPL) status = xd_match (ctxt_p, TM_UNIV|TM_PRIM|ASN_ID_OBJID, &length, XM_ADVANCE); j = 0; while (length > 0 && status == ASN_OK) { /* Parse a subidentifier out of the contents field */ object_p->subid[j] = 0; do { if ((status = xd_memcpy (ctxt_p, &b, 1)) == ASN_OK) { object_p->subid[j] = (object_p->subid[j] * 128) + (b & 0x7F); length--; } } while (b & 0x80 && status == ASN_OK); /* Handle the first subidentifier special case: the first two */ /* sub-id's are encoded into one using the formula (x * 40) + y */ if (j == 0) { subid = object_p->subid[0]; object_p->subid[0] = ((subid / 40) >= 2) ? 2 : subid / 40; object_p->subid[1] = (object_p->subid[0] == 2) ? subid - 80 : subid % 40; j = 2; } else if (++j > ASN_K_MAXSUBIDS) status = ASN_E_INVOBJID; } object_p->numids = j; if (status == ASN_OK && length != 0) status = ASN_E_INVLEN; return (status); } /*********************************************************************** /* /* Routine name: xd_enum /* /* Description: This routine decodes the enumerated value at the current /* message pointer location and returns the value. It /* also advances the message pointer to the start of the /* the next field. /* /* The routine first checks to see if explicit tagging /* is specified. If yes, it calls xd_match to match /* the universal tag for this message type. If the /* match is not successful, a negative value is returned /* to indicate the parse was not successful. /* /* If the match is successful or implicit tagging is /* specified, xd_integer is called to fetch /* the data value. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* tagging bool Specifies whether element is implicitly or /* explicitly tagged. /* length int Length of data to retrieve. Valid for implicit /* case only. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status of operation. Returned as function result. /* object int Decoded enumerated value. /* /**********************************************************************/ int xd_enum (ASN1CTXT *ctxt_p, ASN1ENUM *object_p, ASN1TagType tagging, int length) { register status = ASN_OK; if (tagging == ASN1EXPL) status = xd_match (ctxt_p, TM_UNIV|TM_PRIM|ASN_ID_ENUM, &length, XM_ADVANCE); if (status == ASN_OK) status = xd_integer (ctxt_p, object_p, ASN1IMPL, length); return (status); } /*********************************************************************** /* /* Routine name: xd_real /* /* Description: This routine decodes an ASN.1 real value. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* tagging enum Specifies whether element is implicitly or /* explicitly tagged. /* length int Length of data to retrieve. Valid for implicit /* case only. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status of operation. Returned as function result. /* object int Decoded enumerated value. /* /**********************************************************************/ int xd_real (ASN1CTXT *ctxt_p, ASN1REAL *object_p, ASN1TagType tagging, int length) { unsigned char firstOctet, firstExpOctet, b; int i, status = ASN_OK; unsigned int expLen; double mantissa; unsigned short base; int exponent = 0; if (tagging == ASN1EXPL) { status = xd_match (ctxt_p, TM_UNIV|TM_PRIM|ASN_ID_REAL, &length, XM_ADVANCE); if (status != ASN_OK) return (status); } if (length == 0) { *object_p = 0.0; return (status); } /* fetch first octet */ status = xd_memcpy (ctxt_p, &firstOctet, 1); if (status != ASN_OK) return (status); /* check for special real values (plus/minus infinity) */ if (length == 1) { switch (firstOctet) { case ASN1_K_PLUS_INFINITY: *object_p = xu_GetPlusInfinity (); return (ASN_OK); case ASN1_K_MINUS_INFINITY: *object_p = xu_GetMinusInfinity (); return (ASN_OK); default: return (ASN_E_INVREAL); } } --length; /* Decode normal ASN.1 real value */ if (firstOctet & REAL_BINARY) { switch (firstOctet & REAL_EXPLEN_MASK) { case (REAL_EXPLEN_1): expLen = 1; break; case (REAL_EXPLEN_2): expLen = 2; break; case (REAL_EXPLEN_3): expLen = 3; break; default: { /* long form */ status = xd_memcpy (ctxt_p, &b, 1); if (status != ASN_OK) return (status); expLen = b; --length; } } /* Decode exponent integer */ status = xd_integer (ctxt_p, &exponent, ASN1IMPL, expLen); if (status != ASN_OK) return (status); length -= expLen; /* Now get the mantissa */ mantissa = 0.0; for (i = 0; i < length; i++) { status = xd_memcpy (ctxt_p, &b, 1); if (status != ASN_OK) return (status); mantissa *= (1 << 8); mantissa += b; } /* adjust N by scaling factor */ mantissa *= (1 << ((firstOctet & REAL_FACTOR_MASK) >> 2)); switch(firstOctet & REAL_BASE_MASK) { case (REAL_BASE_2): base = 2; break; case (REAL_BASE_8): base = 8; break; case (REAL_BASE_16): base = 16; break; default: return (ASN_E_INVREAL); } *object_p = mantissa * pow ((double)base, (double)exponent); if (firstOctet & REAL_SIGN) *object_p = -*object_p; } else { /* decimal version */ return (ASN_E_NOTSUPP); /* not supported */ } return (ASN_OK); } /*********************************************************************** /* /* Routine name: xd_any /* /* Description: This routine decodes an X.409 'any' type field. /* An 'any' type is assumed to be a previously encoded /* X.409 value which is to be represented in its native /* form in the returned C structure. The user can then /* apply subsequent decode routine calls to decode the /* value. /* /* This routine simply stores the current X.409 decode /* pointer in the C structure and moves on to the next /* field. /* /* Inputs: /* /* None /* /* Name Type Description /* ---- ---- ----------- /* status int Status of operation. Returned as function result. /* object struct* Structure containing tag, length, and data pointer. /* /**********************************************************************/ int xd_any (ASN1CTXT *ctxt_p, void **object_p2) { int length, status; ASN1TAG tag; /* Store pointer to data in object */ *object_p2 = ctxt_p->buf.ptr; /* Advance decode pointer to the next field */ if ((status = xd_tag_len (ctxt_p, &tag, &length, XM_ADVANCE)) == ASN_OK) { if (length > 0) /* fixed length object */ { ctxt_p->buf.ptr += length; if (ctxt_p->buf.rembytes != ASN_K_INDEFLEN) ctxt_p->buf.rembytes -= length; } else if (length == ASN_K_INDEFLEN) /* indefinite length */ { while ((status = xd_tag_len (ctxt_p, &tag, &length, XM_ADVANCE)) == ASN_OK) { if (!(tag & TM_CONS)) { ctxt_p->buf.ptr += length; /* advance decode pointer */ if (ctxt_p->buf.rembytes != ASN_K_INDEFLEN) ctxt_p->buf.rembytes -= length; /* adjust length */ } } } } /* It is possible to encouter an EOB condition if the ANY field was */ /* defined as an implicit null field and is the last field in the */ /* buffer (this is common in X.410 messages). Assume this is the */ /* case if an ASN_E_ENDOFBUF status is returned from xd_tag_len.. */ if (status == ASN_E_ENDOFBUF) status = ASN_OK; return (status); } /*********************************************************************** /* /* Routine name: xd_setp /* /* Description: This routine initializes the internal buffer pointer /* and message length for decoding an X.409 message. It /* must be called prior to calling any of the other low /* level decode routines. A call to this routine is /* included within each of the high level X.409 decode /* routines. /* /* The routine takes the given message pointer value and /* stores it on a module wide common variable. It then /* parses the message length field to get the overall /* length of the message to be decoded and stores it on /* a common variable as well. This length value is /* returned to the caller as the function result. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* msgptr char* Pointer to the X.409 message to be decoded. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status of operation. Returned as function result. /* tag struct X.409 tag located at message pointer. /* length int Length of message component. Returned as follows: /* >= 0 component is fixed length /* ASN_K_INDEFLEN component is indefinite length /* /**********************************************************************/ int xd_setp (ASN1CTXT *ctxt_p, ASN1OCTET *msg_p, int msglen, ASN1TAG *tag_p, int *len_p) { int stat, ll; ASN1TAG ltag; /* Pre-parse message to get overall message length */ memset (ctxt_p, 0, sizeof(ASN1CTXT)); ctxt_p->buf.ptr = msg_p; ctxt_p->buf.rembytes = (msglen > 0) ? msglen : INT_MAX; /* If message is fixed length, add length of ID and length fields */ /* onto contents field length to get total message length; else set */ /* global message length to indefinite length indicator value... */ stat = xd_tag_len (ctxt_p, <ag, &ll, XM_ADVANCE); ctxt_p->buf.rembytes = (ll == ASN_K_INDEFLEN) ? ll : ll + (ctxt_p->buf.ptr - msg_p); ctxt_p->buf.ptr = msg_p; ctxt_p->buf.ilcnt = 0; if (tag_p) *tag_p = ltag; if (len_p) *len_p = ctxt_p->buf.rembytes; return (stat); } /*********************************************************************** /* /* Routine name: xd_indeflen /* /* Description: This calculates the actual length of an indefinite /* message. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* msgptr char* Pointer to indefinite length ASN.1 message. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Status/length value. If >= 0, indicates actual /* length of the message; if < 0, error status. /* /**********************************************************************/ int xd_indeflen (ASN1OCTET* msg_p) { ASN1CTXT ctxt; ASN1TAG tag; int len, stat; if ((stat = xd_setp (&ctxt, msg_p, 0, &tag, &len)) != ASN_OK) return (stat); if (len != ASN_K_INDEFLEN) return (ASN_E_INVLEN); ctxt.buf.start_p = ctxt.buf.ptr; /* Advance decode pointer to end of buffer */ while ((stat = xd_tag_len (&ctxt, &tag, &len, XM_ADVANCE)) == ASN_OK) if (len > 0) ctxt.buf.ptr += len; if (stat != ASN_E_ENDOFBUF) return (stat); else return (ctxt.buf.ptr - ctxt.buf.start_p); } /*********************************************************************** /* /* INTERNAL ROUTINES: These routines for internal use only within the /* X.409 low level decode module. /* /**********************************************************************/ /*********************************************************************** /* /* Routine name: xd_memcpy /* /* Description: This routine handles memory transfers required during /* the decoding of a message. It copies data from the /* message buffer to the given object. The overall /* message length is decremented as the copy occurs in /* order to keep track of the relative pointer position in /* in the buffer. Attempts to copy data from past the end /* of the buffer will result in an error. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* length int Number of bytes to copy. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* length int Actual length of data copied. Returned as /* function result. /* object char* Pointer to destination object. /* /**********************************************************************/ int xd_memcpy (ASN1CTXT* ctxt_p, ASN1OCTET *object_p, int length) { register i, do_copy; if (ctxt_p->buf.rembytes == ASN_K_INDEFLEN) do_copy = TRUE; else do_copy = ((ctxt_p->buf.rembytes -= length) >= 0); if (do_copy) { memcpy (object_p, ctxt_p->buf.ptr, length); ctxt_p->buf.ptr += length; return (ASN_OK); } else return (ASN_E_ENDOFBUF); } /*********************************************************************** /* /* Routine name: xd_len /* /* Description: This routine decodes the length field component of an /* X.409 message. It is called by the xd_tag_len routine /* which handles the decoding of both the ID and length /* fields. /* /* Inputs: /* /* None /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Operation status returned as function result /* length int Decoded length value returned as function result /* as follows: /* >= 0 fixed length /* ASN_K_INDEFLEN indefinite length /* /**********************************************************************/ int xd_len (ASN1CTXT *ctxt_p, int *len_p) { ASN1OCTET i, b; register stat; *len_p = 0; if ((stat = xd_memcpy (ctxt_p, &b, 1)) == ASN_OK) { if (b > 0x80) { for (i = b & 0x7F, *len_p = 0; i > 0; i--) if ((stat = xd_memcpy (ctxt_p, &b, 1)) == ASN_OK) *len_p = (*len_p * 256) + b; else return (stat); } else if (b == 0x80) *len_p = ASN_K_INDEFLEN; else *len_p = b; if (ctxt_p->buf.rembytes != ASN_K_INDEFLEN && *len_p != ASN_K_INDEFLEN) if (*len_p < 0 || *len_p > ctxt_p->buf.rembytes) stat = ASN_E_INVLEN; } return (stat); } /*********************************************************************** /* /* Routine name: xd_chkend /* /* Description: This routine checks for the end of the context defined /* by the length variables that were last pushed on the /* stack using xd_push. /* /* Inputs: /* /* None /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* eoc bool True if end-of-context encountered. Returned as /* function result. /* /**********************************************************************/ int xd_chkend (ASN1CTXT* ctxt_p, ASN1CCB* ccb_p) { int len; ASN1TAG tag; register eoc, stat, usedBytes; if (ccb_p->len == ASN_K_INDEFLEN) { stat = xd_tag_len (ctxt_p, &tag, &len, 0); if ((stat == ASN_E_ENDOFBUF) || (tag == 0 && len == 0)) { ctxt_p->buf.ptr += 2; eoc = TRUE; } else eoc = FALSE; } else { usedBytes = ctxt_p->buf.ptr - ccb_p->ptr; eoc = (usedBytes >= ccb_p->len); } return (eoc); } /*********************************************************************** /* /* Routine name: xd_count /* /* Description: This routine counts the elements within a sequence of or /* set of constructor field. /* /* Inputs: /* /* Name Type Description /* ---- ---- ----------- /* length int Length of sequence of or set of constructor field. /* /* Outputs: /* /* Name Type Description /* ---- ---- ----------- /* stat int Routine completion status. Returned as function /* result. /* count int Number of elements in field. /* /**********************************************************************/ int xd_count (ASN1CTXT *ctxt_p, int length, int *count_p) { ASN1BUF saved_ctxt; ASN1TAG tag; ASN1CCB ccb; int len, stat = ASN_OK; /* Save current decoding context */ memcpy (&saved_ctxt, &ctxt_p->buf, sizeof(ASN1BUF)); /* Count elements */ *count_p = 0; ccb.len = length; ccb.ptr = ctxt_p->buf.ptr; while (!xd_chkend (ctxt_p, &ccb) && stat == ASN_OK) if ((stat = xd_tag_len (ctxt_p, &tag, &len, XM_ADVANCE)) == ASN_OK) { if (len > 0) { ctxt_p->buf.ptr += len; (*count_p)++; } else if (len != ASN_K_INDEFLEN) return (ASN_E_INVLEN); } /* Restore original message pointer and length */ memcpy (&ctxt_p->buf, &saved_ctxt, sizeof(ASN1BUF)); return (stat); }