diff --git a/libs/yasn/asn.cpp b/libs/yasn/asn.cpp index 33d6d151..f6dd0e59 100644 --- a/libs/yasn/asn.cpp +++ b/libs/yasn/asn.cpp @@ -43,8 +43,10 @@ int ASNLib::decodeLength(DataBlock& data) { if (lengthByte & ASN_LONG_LENGTH) { // the length is represented on more than one byte lengthByte &= ~ASN_LONG_LENGTH; /* turn MSB off */ - if (lengthByte == 0) - return InvalidLengthOrTag; + if (lengthByte == 0) { + data.cut(-1); + return IndefiniteForm; + } if (lengthByte > sizeof(int)) return InvalidLengthOrTag; @@ -88,6 +90,54 @@ DataBlock ASNLib::buildLength(DataBlock& data) return lenDb; } +int ASNLib::matchEOC(DataBlock& data) +{ + /** + * EoC = 00 00 + */ + XDebug(s_libName.c_str(),DebugAll,"::matchEOC() in data='%p'",&data); + if (data.length() < 2) + return InvalidLengthOrTag; + if (data[0] == 0 && data[1] == 0) { + data.cut(-2); + return 2; + } + return InvalidLengthOrTag; +} + + +int ASNLib::parseUntilEoC(DataBlock& data, int length) +{ + if (length >= (int)data.length() || ASNLib::matchEOC(data) > 0) + return length; + while (data.length() && ASNLib::matchEOC(data) < 0) { + // compute tag portion length + AsnTag tag; + AsnTag::decode(tag,data); + length += tag.coding().length(); + data.cut(-tag.coding().length()); + // compute length portion length + int initLen = data.length(); + int len = ASNLib::decodeLength(data); + length += initLen - data.length(); + + bool checkEoC = (len == ASNLib::IndefiniteForm); + if (!checkEoC && len < 0) + return length; + + if (checkEoC) { + length = parseUntilEoC(data,length); + if (ASNLib::matchEOC(data) > 0) + length += 2; + } + else { + length += len; + data.cut(-len); + } + } + return length; +} + int ASNLib::decodeBoolean(DataBlock& data, bool* val, bool tagCheck) { /** diff --git a/libs/yasn/yateasn.h b/libs/yasn/yateasn.h index 4b2799ea..20d3ce8d 100644 --- a/libs/yasn/yateasn.h +++ b/libs/yasn/yateasn.h @@ -745,8 +745,9 @@ public: enum Error { InvalidLengthOrTag = -1, ConstraintBreakError = -2, - ParseError, - InvalidContentsError + ParseError = -3, + InvalidContentsError = -4, + IndefiniteForm = -5, }; /** @@ -1084,6 +1085,21 @@ public: * @return The length of the data block length encoding */ static int encodeSet(DataBlock& data, bool tagCheck); + + /** + * Verify the data for End Of Contents presence + * @param data Input block to verify + * @return Length of data consumed from the input data it the decoding was succesful, it should be 2 in case of success, -1 if the data doesn't match EoC + */ + static int matchEOC(DataBlock& data); + + /** + * Extract length until a End Of Contents is found. + * @param data Input block for which to determine the length to End Of Contents + * @param length Length to which to add determined length + * @return Length until End Of Contents + */ + static int parseUntilEoC(DataBlock& data, int length = 0); }; } diff --git a/libs/ysig/tcap.cpp b/libs/ysig/tcap.cpp index 335d2869..2abe6fa0 100644 --- a/libs/ysig/tcap.cpp +++ b/libs/ysig/tcap.cpp @@ -2529,13 +2529,16 @@ SS7TCAPError SS7TCAPTransactionANSI::decodeComponents(NamedList& params, DataBlo // decode length of component portion int len = ASNLib::decodeLength(data); - if (len < 0 || len != (int)data.length()) { // the length of the remaining data should be the same as the decoded length() + bool checkEoC = (len == ASNLib::IndefiniteForm); + if (!checkEoC && (len < 0 || len != (int)data.length())) { // the length of the remaining data should be the same as the decoded length() error.setError(SS7TCAPError::General_BadlyStructuredCompPortion); return error; } unsigned int compCount = 0; while (data.length()) { + if (checkEoC && ASNLib::matchEOC(data) > 0) + break; compCount++; // decode component type u_int8_t compType = data[0]; @@ -4087,13 +4090,16 @@ SS7TCAPError SS7TCAPTransactionITU::decodeComponents(NamedList& params, DataBloc // decode length of component portion int len = ASNLib::decodeLength(data); - if (len < 0 || len != (int)data.length()) { // the length of the remaining data should be the same as the decoded length + bool checkEoC = (len == ASNLib::IndefiniteForm); + if (!checkEoC && (len < 0 || len != (int)data.length())) { // the length of the remaining data should be the same as the decoded length error.setError(SS7TCAPError::General_BadlyStructuredCompPortion); return error; } unsigned int compCount = 0; while (data.length()) { + if (checkEoC && ASNLib::matchEOC(data) > 0) + break; compCount++; // decode component type u_int8_t compType = data[0]; diff --git a/modules/sig/camel_map.cpp b/modules/sig/camel_map.cpp index 7fba6ae7..3d2a72d2 100644 --- a/modules/sig/camel_map.cpp +++ b/modules/sig/camel_map.cpp @@ -920,11 +920,21 @@ static bool decodeHex(const Parameter* param, MapCamelType* type, AsnTag& tag, D child->setAttribute(s_encAttr,"hex"); int len = ASNLib::decodeLength(data); - if (len < 0) + bool checkEoC = (len == ASNLib::IndefiniteForm && tag.type() == AsnTag::Constructor); + if (!checkEoC && len < 0) return false; String octets; - octets.hexify(data.data(),(len > (int)data.length() ? data.length() : len),' '); - data.cut(-len); + if (checkEoC) { + DataBlock d(data.data(),data.length()); + int l = ASNLib::parseUntilEoC(d); + octets.hexify(data.data(),l,' '); + data.cut(-l); + ASNLib::matchEOC(data); + } + else { + octets.hexify(data.data(),(len > (int)data.length() ? data.length() : len),' '); + data.cut(-len); + } child->addText(octets); return true; } @@ -1051,7 +1061,9 @@ static bool decodeSeq(const Parameter* param, MapCamelType* type, AsnTag& tag, D data.cut(-(int)tag.coding().length()); int len = ASNLib::decodeLength(data); - if (len < 0) + bool checkEoC = (len == ASNLib::IndefiniteForm); + len = (checkEoC ? data.length() : len); + if (!checkEoC && len < 0) return false; int initLen = data.length(); @@ -1061,7 +1073,7 @@ static bool decodeSeq(const Parameter* param, MapCamelType* type, AsnTag& tag, D if (param->content) { const Parameter* params= static_cast(param->content); while (params && params->name) { - if (initLen - (int)data.length() >= len) + if ((initLen - (int)data.length() >= len) || (checkEoC && ASNLib::matchEOC(data) > 0)) break; AsnTag childTag; AsnTag::decode(childTag,data); @@ -1133,16 +1145,19 @@ static bool decodeSeqOf(const Parameter* param, MapCamelType* type, AsnTag& tag, data.cut(-(int)tag.coding().length()); int len = ASNLib::decodeLength(data); - if (len < 0) + bool checkEoC = (len == ASNLib::IndefiniteForm); + if (!checkEoC && len < 0) return false; XmlElement* child = new XmlElement(param->name); parent->addChild(child); int initLength = data.length(); - int payloadLen = len; + int payloadLen = (checkEoC ? data.length() : len); if (param->content) { const Parameter* params= static_cast(param->content); while (params && !TelEngine::null(params->name) && payloadLen) { + if (checkEoC && ASNLib::matchEOC(data) > 0) + break; AsnTag childTag; AsnTag::decode(childTag,data); if (!decodeParam(params,childTag,data,child,addEnc,err)) { @@ -1214,12 +1229,14 @@ static bool decodeChoice(const Parameter* param, MapCamelType* type, AsnTag& tag return false; XDebug(&__plugin,DebugAll,"decodeChoice(param=%s[%p],elem=%s[%p],datalen=%d)",param->name.c_str(),param,parent->getTag().c_str(), parent,data.length()); + bool checkEoC = false; if (param->tag != s_noTag) { if (param->tag != tag) return false; data.cut(-(int)tag.coding().length()); int len = ASNLib::decodeLength(data); - if (len < 0) + checkEoC = (len == ASNLib::IndefiniteForm); + if (!checkEoC && len < 0) return false; } XmlElement* child = new XmlElement(param->name); @@ -1234,6 +1251,8 @@ static bool decodeChoice(const Parameter* param, MapCamelType* type, AsnTag& tag params++; continue; } + if (checkEoC) + ASNLib::matchEOC(data); return true; } if (err != TcapXApplication::DataMissing) {