1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822 |
- //+-------------------------------------------------------------------------------+
- //| Copyright (c) 2003 Liping Dai. All rights reserved. |
- //| Web: www.lipingshare.com |
- //| Email: lipingshare@yahoo.com |
- //| |
- //| Copyright and Permission Details: |
- //| ================================= |
- //| Permission is hereby granted, free of charge, to any person obtaining a copy |
- //| of this software and associated documentation files (the "Software"), to deal |
- //| in the Software without restriction, including without limitation the rights |
- //| to use, copy, modify, merge, publish, distribute, and/or sell copies of the |
- //| Software, subject to the following conditions: |
- //| |
- //| 1. Redistributions of source code must retain the above copyright notice, this|
- //| list of conditions and the following disclaimer. |
- //| |
- //| 2. Redistributions in binary form must reproduce the above copyright notice, |
- //| this list of conditions and the following disclaimer in the documentation |
- //| and/or other materials provided with the distribution. |
- //| |
- //| THE SOFTWARE PRODUCT IS PROVIDED �AS IS� WITHOUT WARRANTY OF ANY KIND, |
- //| EITHER EXPRESS OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED |
- //| WARRANTIES OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR |
- //| A PARTICULAR PURPOSE. |
- //+-------------------------------------------------------------------------------+
-
-
- using System;
- using System.IO;
- using System.Collections;
- using System.Linq;
- using System.Text;
- using UnityEngine;
-
- namespace LipingShare.LCLib.Asn1Processor
- {
- /// <summary>
- /// Asn1Node, implemented IAsn1Node interface.
- /// </summary>
- internal class Asn1Node : IAsn1Node
- {
- // PrivateMembers
- private byte tag;
- private long dataOffset;
- private long dataLength;
- private long lengthFieldBytes;
- private byte[] data;
- private ArrayList childNodeList;
- private byte unusedBits;
- private long deepness;
- private string path = "";
- private const int indentStep = 3;
- private Asn1Node parentNode;
- private bool requireRecalculatePar = true;
- private bool isIndefiniteLength = false;
- private bool parseEncapsulatedData = true;
-
- /// <summary>
- /// Default Asn1Node text line length.
- /// </summary>
- public const int defaultLineLen = 80;
-
- /// <summary>
- /// Minium line length.
- /// </summary>
- public const int minLineLen = 60;
-
- const int k_EndOfStream = -1;
- const int k_InvalidIndeterminateContentLength = -1;
- const int k_IndefiniteLengthFooterSize = 2;
-
- private Asn1Node(Asn1Node parentNode, long dataOffset)
- {
- Init();
- deepness = parentNode.Deepness + 1;
- this.parentNode = parentNode;
- this.dataOffset = dataOffset;
- }
-
- private void Init()
- {
- childNodeList = new ArrayList();
- data = null;
- dataLength = 0;
- lengthFieldBytes = 0;
- unusedBits = 0;
- tag = Asn1Tag.SEQUENCE | Asn1TagClasses.CONSTRUCTED;
- childNodeList.Clear();
- deepness = 0;
- parentNode = null;
- }
-
- private string GetHexPrintingStr(Asn1Node startNode, string baseLine,
- string lStr, int lineLen)
- {
- string nodeStr = "";
- string iStr = GetIndentStr(startNode);
- string dataStr = Asn1Util.ToHexString(data);
- if (dataStr.Length > 0)
- {
- if (baseLine.Length + dataStr.Length < lineLen)
- {
- nodeStr += baseLine + "'" + dataStr + "'";
- }
- else
- {
- nodeStr += baseLine + FormatLineHexString(
- lStr,
- iStr.Length,
- lineLen,
- dataStr
- );
- }
- }
- else
- {
- nodeStr += baseLine;
- }
- return nodeStr + "\r\n";
- }
-
- private string FormatLineString(string lStr, int indent, int lineLen, string msg)
- {
- string retval = "";
- indent += indentStep;
- int realLen = lineLen - indent;
- int sLen = indent;
- int currentp;
- for (currentp = 0; currentp < msg.Length; currentp += realLen)
- {
- if (currentp + realLen > msg.Length)
- {
- retval += "\r\n" + lStr + Asn1Util.GenStr(sLen, ' ') +
- "'" + msg.Substring(currentp, msg.Length - currentp) + "'";
- }
- else
- {
- retval += "\r\n" + lStr + Asn1Util.GenStr(sLen, ' ') + "'" +
- msg.Substring(currentp, realLen) + "'";
- }
- }
- return retval;
- }
-
- private string FormatLineHexString(string lStr, int indent, int lineLen, string msg)
- {
- string retval = "";
- indent += indentStep;
- int realLen = lineLen - indent;
- int sLen = indent;
- int currentp;
- for (currentp = 0; currentp < msg.Length; currentp += realLen)
- {
- if (currentp + realLen > msg.Length)
- {
- retval += "\r\n" + lStr + Asn1Util.GenStr(sLen, ' ') +
- msg.Substring(currentp, msg.Length - currentp);
- }
- else
- {
- retval += "\r\n" + lStr + Asn1Util.GenStr(sLen, ' ') +
- msg.Substring(currentp, realLen);
- }
- }
- return retval;
- }
-
-
- //PublicMembers
-
- /// <summary>
- /// Constructor, initialize all the members.
- /// </summary>
- public Asn1Node()
- {
- Init();
- dataOffset = 0;
- }
-
- /// <summary>
- /// Get/Set isIndefiniteLength.
- /// </summary>
- public bool IsIndefiniteLength
- {
- get
- {
- return isIndefiniteLength;
- }
- set
- {
- isIndefiniteLength = value;
- }
- }
-
- /// <summary>
- /// Clone a new Asn1Node by current node.
- /// </summary>
- /// <returns>new node.</returns>
- public Asn1Node Clone()
- {
- MemoryStream ms = new MemoryStream();
- this.SaveData(ms);
- ms.Position = 0;
- Asn1Node node = new Asn1Node();
- node.LoadData(ms);
- return node;
- }
-
- /// <summary>
- /// Get/Set tag value.
- /// </summary>
- public byte Tag
- {
- get
- {
- return tag;
- }
- set
- {
- tag = value;
- }
- }
-
- public byte MaskedTag
- {
- get
- {
- return (byte)(tag & Asn1Tag.TAG_MASK);
- }
- }
-
- /// <summary>
- /// Load data from byte[].
- /// </summary>
- /// <param name="byteData">byte[]</param>
- /// <returns>true:Succeed; false:failed.</returns>
- public bool LoadData(byte[] byteData)
- {
- bool retval = true;
- try
- {
- MemoryStream ms = new MemoryStream(byteData);
- ms.Position = 0;
- retval = LoadData(ms);
- ms.Close();
- }
- catch
- {
- retval = false;
- }
- return retval;
- }
-
- /// <summary>
- /// Retrieve all the node count in the node subtree.
- /// </summary>
- /// <param name="node">starting node.</param>
- /// <returns>long integer node count in the node subtree.</returns>
- public static long GetDescendantNodeCount(Asn1Node node)
- {
- long count = 0;
- count += node.ChildNodeCount;
- for (int i = 0; i < node.ChildNodeCount; i++)
- {
- count += GetDescendantNodeCount(node.GetChildNode(i));
- }
- return count;
- }
-
- /// <summary>
- /// Load data from Stream. Start from current position.
- /// This function sets requireRecalculatePar to false then calls InternalLoadData
- /// to complish the task.
- /// </summary>
- /// <param name="xdata">Stream</param>
- /// <returns>true:Succeed; false:failed.</returns>
- public bool LoadData(Stream xdata)
- {
- bool retval = false;
- try
- {
- RequireRecalculatePar = false;
- retval = InternalLoadData(xdata);
- return retval;
- }
- finally
- {
- RequireRecalculatePar = true;
- RecalculateTreePar();
- }
- }
-
- /// <summary>
- /// Call SaveData and return byte[] as result instead stream.
- /// </summary>
- /// <returns></returns>
- public byte[] GetRawData()
- {
- MemoryStream ms = new MemoryStream();
- SaveData(ms);
- byte[] retval = new byte[ms.Length];
- ms.Position = 0;
- ms.Read(retval, 0, (int)ms.Length);
- ms.Close();
- return retval;
- }
-
- /// <summary>
- /// Get if data is empty.
- /// </summary>
- public bool IsEmptyData
- {
- get
- {
- if (data == null) return true;
- if (data.Length < 1)
- return true;
- else
- return false;
- }
- }
-
- /// <summary>
- /// Save node data into Stream.
- /// </summary>
- /// <param name="xdata">Stream.</param>
- /// <returns>true:Succeed; false:failed.</returns>
- public bool SaveData(Stream xdata)
- {
- bool retval = true;
- long nodeCount = ChildNodeCount;
- xdata.WriteByte(tag);
- Asn1Util.DERLengthEncode(xdata, (ulong)dataLength);
- if ((tag) == Asn1Tag.BIT_STRING)
- {
- xdata.WriteByte(unusedBits);
- }
- if (nodeCount == 0)
- {
- if (data != null)
- {
- xdata.Write(data, 0, data.Length);
- }
- }
- else
- {
- Asn1Node tempNode;
- int i;
- for (i = 0; i < nodeCount; i++)
- {
- tempNode = GetChildNode(i);
- retval = tempNode.SaveData(xdata);
- }
- }
- return retval;
- }
-
- /// <summary>
- /// Clear data and children list.
- /// </summary>
- public void ClearAll()
- {
- data = null;
- Asn1Node tempNode;
- for (int i = 0; i < childNodeList.Count; i++)
- {
- tempNode = (Asn1Node)childNodeList[i];
- tempNode.ClearAll();
- }
- childNodeList.Clear();
- RecalculateTreePar();
- }
-
-
- /// <summary>
- /// Add child node at the end of children list.
- /// </summary>
- /// <param name="xdata">the node that will be add in.</param>
- public void AddChild(Asn1Node xdata)
- {
- childNodeList.Add(xdata);
- RecalculateTreePar();
- }
-
- /// <summary>
- /// Insert a node in the children list before the pointed index.
- /// </summary>
- /// <param name="xdata">Asn1Node</param>
- /// <param name="index">0 based index.</param>
- /// <returns>New node index.</returns>
- public int InsertChild(Asn1Node xdata, int index)
- {
- childNodeList.Insert(index, xdata);
- RecalculateTreePar();
- return index;
- }
-
- /// <summary>
- /// Insert a node in the children list before the pointed node.
- /// </summary>
- /// <param name="xdata">Asn1Node that will be instered in the children list.</param>
- /// <param name="indexNode">Index node.</param>
- /// <returns>New node index.</returns>
- public int InsertChild(Asn1Node xdata, Asn1Node indexNode)
- {
- int index = childNodeList.IndexOf(indexNode);
- childNodeList.Insert(index, xdata);
- RecalculateTreePar();
- return index;
- }
-
- /// <summary>
- /// Insert a node in the children list after the pointed node.
- /// </summary>
- /// <param name="xdata">Asn1Node</param>
- /// <param name="indexNode">Index node.</param>
- /// <returns>New node index.</returns>
- public int InsertChildAfter(Asn1Node xdata, Asn1Node indexNode)
- {
- int index = childNodeList.IndexOf(indexNode) + 1;
- childNodeList.Insert(index, xdata);
- RecalculateTreePar();
- return index;
- }
-
- /// <summary>
- /// Insert a node in the children list after the pointed node.
- /// </summary>
- /// <param name="xdata">Asn1Node that will be instered in the children list.</param>
- /// <param name="index">0 based index.</param>
- /// <returns>New node index.</returns>
- public int InsertChildAfter(Asn1Node xdata, int index)
- {
- int xindex = index + 1;
- childNodeList.Insert(xindex, xdata);
- RecalculateTreePar();
- return xindex;
- }
-
- /// <summary>
- /// Remove a child from children node list by index.
- /// </summary>
- /// <param name="index">0 based index.</param>
- /// <returns>The Asn1Node just removed from the list.</returns>
- public Asn1Node RemoveChild(int index)
- {
- Asn1Node retval = null;
- if (index < (childNodeList.Count - 1))
- {
- retval = (Asn1Node)childNodeList[index + 1];
- }
- childNodeList.RemoveAt(index);
- if (retval == null)
- {
- if (childNodeList.Count > 0)
- {
- retval = GetLastChild();
- }
- else
- {
- retval = this;
- }
- }
- RecalculateTreePar();
- return retval;
- }
-
- Asn1Node GetLastChild()
- {
- return (Asn1Node)childNodeList[childNodeList.Count - 1];
- }
-
- /// <summary>
- /// Remove the child from children node list.
- /// </summary>
- /// <param name="node">The node needs to be removed.</param>
- /// <returns></returns>
- public Asn1Node RemoveChild(Asn1Node node)
- {
- Asn1Node retval = null;
- int i = childNodeList.IndexOf(node);
- retval = RemoveChild(i);
- return retval;
- }
-
- /// <summary>
- /// Get child node count.
- /// </summary>
- public long ChildNodeCount
- {
- get
- {
- return childNodeList.Count;
- }
- }
-
- /// <summary>
- /// Retrieve child node by index.
- /// </summary>
- /// <param name="index">0 based index.</param>
- /// <returns>0 based index.</returns>
- public Asn1Node GetChildNode(int index)
- {
- Asn1Node retval = null;
- if (index < ChildNodeCount)
- {
- retval = (Asn1Node)childNodeList[index];
- }
- return retval;
- }
-
-
-
- /// <summary>
- /// Get tag name.
- /// </summary>
- public string TagName
- {
- get
- {
- return Asn1Util.GetTagName(tag);
- }
- }
-
- /// <summary>
- /// Get parent node.
- /// </summary>
- public Asn1Node ParentNode
- {
- get
- {
- return parentNode;
- }
- }
-
- /// <summary>
- /// Get the node and all the descendents text description.
- /// </summary>
- /// <param name="startNode">starting node.</param>
- /// <param name="lineLen">line length.</param>
- /// <returns></returns>
- public string GetText(Asn1Node startNode, int lineLen)
- {
- string nodeStr = "";
- string baseLine = "";
- string dataStr = "";
- const string lStr = " | | | ";
- string oid, oidName;
- switch (tag)
- {
- case Asn1Tag.BIT_STRING:
- baseLine =
- String.Format("{0,6}|{1,6}|{2,7}|{3} {4} UnusedBits:{5} : ",
- dataOffset,
- dataLength,
- lengthFieldBytes,
- GetIndentStr(startNode),
- TagName,
- unusedBits
- );
- dataStr = Asn1Util.ToHexString(data);
- if (baseLine.Length + dataStr.Length < lineLen)
- {
- if (dataStr.Length < 1)
- {
- nodeStr += baseLine + "\r\n";
- }
- else
- {
- nodeStr += baseLine + "'" + dataStr + "'\r\n";
- }
- }
- else
- {
- nodeStr += baseLine + FormatLineHexString(
- lStr,
- GetIndentStr(startNode).Length,
- lineLen,
- dataStr + "\r\n"
- );
- }
- break;
- case Asn1Tag.OBJECT_IDENTIFIER:
- Oid xoid = new Oid();
- oid = xoid.Decode(new MemoryStream(data));
- oidName = xoid.GetOidName(oid);
- nodeStr += String.Format("{0,6}|{1,6}|{2,7}|{3} {4} : {5} [{6}]\r\n",
- dataOffset,
- dataLength,
- lengthFieldBytes,
- GetIndentStr(startNode),
- TagName,
- oidName,
- oid
- );
- break;
- case Asn1Tag.RELATIVE_OID:
- RelativeOid xiod = new RelativeOid();
- oid = xiod.Decode(new MemoryStream(data));
- oidName = "";
- nodeStr += String.Format("{0,6}|{1,6}|{2,7}|{3} {4} : {5} [{6}]\r\n",
- dataOffset,
- dataLength,
- lengthFieldBytes,
- GetIndentStr(startNode),
- TagName,
- oidName,
- oid
- );
- break;
- case Asn1Tag.PRINTABLE_STRING:
- case Asn1Tag.IA5_STRING:
- case Asn1Tag.UNIVERSAL_STRING:
- case Asn1Tag.VISIBLE_STRING:
- case Asn1Tag.NUMERIC_STRING:
- case Asn1Tag.UTC_TIME:
- case Asn1Tag.UTF8_STRING:
- case Asn1Tag.BMPSTRING:
- case Asn1Tag.GENERAL_STRING:
- case Asn1Tag.GENERALIZED_TIME:
- baseLine =
- String.Format("{0,6}|{1,6}|{2,7}|{3} {4} : ",
- dataOffset,
- dataLength,
- lengthFieldBytes,
- GetIndentStr(startNode),
- TagName
- );
- if (tag == Asn1Tag.UTF8_STRING)
- {
- UTF8Encoding unicode = new UTF8Encoding();
- dataStr = unicode.GetString(data);
- }
- else
- {
- dataStr = Asn1Util.BytesToString(data);
- }
- if (baseLine.Length + dataStr.Length < lineLen)
- {
- nodeStr += baseLine + "'" + dataStr + "'\r\n";
- }
- else
- {
- nodeStr += baseLine + FormatLineString(
- lStr,
- GetIndentStr(startNode).Length,
- lineLen,
- dataStr) + "\r\n";
- }
- break;
- case Asn1Tag.INTEGER:
- if (data != null && dataLength < 8)
- {
- nodeStr += String.Format("{0,6}|{1,6}|{2,7}|{3} {4} : {5}\r\n",
- dataOffset,
- dataLength,
- lengthFieldBytes,
- GetIndentStr(startNode),
- TagName,
- Asn1Util.BytesToLong(data).ToString()
- );
- }
- else
- {
- baseLine =
- String.Format("{0,6}|{1,6}|{2,7}|{3} {4} : ",
- dataOffset,
- dataLength,
- lengthFieldBytes,
- GetIndentStr(startNode),
- TagName
- );
- nodeStr += GetHexPrintingStr(startNode, baseLine, lStr, lineLen);
- }
- break;
- default:
- if ((tag & Asn1Tag.TAG_MASK) == 6) // Visible string for certificate
- {
- baseLine =
- String.Format("{0,6}|{1,6}|{2,7}|{3} {4} : ",
- dataOffset,
- dataLength,
- lengthFieldBytes,
- GetIndentStr(startNode),
- TagName
- );
- dataStr = Asn1Util.BytesToString(data);
- if (baseLine.Length + dataStr.Length < lineLen)
- {
- nodeStr += baseLine + "'" + dataStr + "'\r\n";
- }
- else
- {
- nodeStr += baseLine + FormatLineString(
- lStr,
- GetIndentStr(startNode).Length,
- lineLen,
- dataStr) + "\r\n";
- }
- }
- else
- {
- baseLine =
- String.Format("{0,6}|{1,6}|{2,7}|{3} {4} : ",
- dataOffset,
- dataLength,
- lengthFieldBytes,
- GetIndentStr(startNode),
- TagName
- );
- nodeStr += GetHexPrintingStr(startNode, baseLine, lStr, lineLen);
- }
- break;
- };
- if (childNodeList.Count >= 0)
- {
- nodeStr += GetListStr(startNode, lineLen);
- }
- return nodeStr;
- }
-
- /// <summary>
- /// Get the path string of the node.
- /// </summary>
- public string Path
- {
- get
- {
- return path;
- }
- }
-
- /// <summary>
- /// Retrieve the node description.
- /// </summary>
- /// <param name="pureHexMode">true:Return hex string only;
- /// false:Convert to more readable string depending on the node tag.</param>
- /// <returns>string</returns>
- public string GetDataStr(bool pureHexMode)
- {
- const int lineLen = 32;
- string dataStr = "";
- if (pureHexMode)
- {
- dataStr = Asn1Util.FormatString(Asn1Util.ToHexString(data), lineLen, 2);
- }
- else
- {
- switch (tag)
- {
- case Asn1Tag.BIT_STRING:
- dataStr = Asn1Util.FormatString(Asn1Util.ToHexString(data), lineLen, 2);
- break;
- case Asn1Tag.OBJECT_IDENTIFIER:
- Oid xoid = new Oid();
- dataStr = xoid.Decode(new MemoryStream(data));
- break;
- case Asn1Tag.RELATIVE_OID:
- RelativeOid roid = new RelativeOid();
- dataStr = roid.Decode(new MemoryStream(data));
- break;
- case Asn1Tag.PRINTABLE_STRING:
- case Asn1Tag.IA5_STRING:
- case Asn1Tag.UNIVERSAL_STRING:
- case Asn1Tag.VISIBLE_STRING:
- case Asn1Tag.NUMERIC_STRING:
- case Asn1Tag.UTC_TIME:
- case Asn1Tag.BMPSTRING:
- case Asn1Tag.GENERAL_STRING:
- case Asn1Tag.GENERALIZED_TIME:
- dataStr = Asn1Util.BytesToString(data);
- break;
- case Asn1Tag.UTF8_STRING:
- UTF8Encoding utf8 = new UTF8Encoding();
- dataStr = utf8.GetString(data);
- break;
- case Asn1Tag.INTEGER:
- dataStr = Asn1Util.FormatString(Asn1Util.ToHexString(data), lineLen, 2);
- break;
- default:
- if ((tag & Asn1Tag.TAG_MASK) == 6) // Visible string for certificate
- {
- dataStr = Asn1Util.BytesToString(data);
- }
- else
- {
- dataStr = Asn1Util.FormatString(Asn1Util.ToHexString(data), lineLen, 2);
- }
- break;
- };
- }
- return dataStr;
- }
-
- /// <summary>
- /// Get node label string.
- /// </summary>
- /// <param name="mask">
- /// <code>
- /// SHOW_OFFSET
- /// SHOW_DATA
- /// USE_HEX_OFFSET
- /// SHOW_TAG_NUMBER
- /// SHOW_PATH</code>
- /// </param>
- /// <returns>string</returns>
- public string GetLabel(uint mask)
- {
- string nodeStr = "";
- string dataStr = "";
- string offsetStr = "";
- if ((mask & TagTextMask.USE_HEX_OFFSET) != 0)
- {
- if ((mask & TagTextMask.SHOW_TAG_NUMBER) != 0)
- offsetStr = String.Format("(0x{0:X2},0x{1:X6},0x{2:X4})", tag, dataOffset, dataLength);
- else
- offsetStr = String.Format("(0x{0:X6},0x{1:X4})", dataOffset, dataLength);
- }
- else
- {
- if ((mask & TagTextMask.SHOW_TAG_NUMBER) != 0)
- offsetStr = String.Format("({0},{1},{2})", tag, dataOffset, dataLength);
- else
- offsetStr = String.Format("({0},{1})", dataOffset, dataLength);
- }
- string oid, oidName;
- switch (tag)
- {
- case Asn1Tag.BIT_STRING:
- if ((mask & TagTextMask.SHOW_OFFSET) != 0)
- {
- nodeStr += offsetStr;
- }
- nodeStr += " " + TagName + " UnusedBits: " + unusedBits.ToString();
- if ((mask & TagTextMask.SHOW_DATA) != 0)
- {
- dataStr = Asn1Util.ToHexString(data);
- nodeStr += ((dataStr.Length > 0) ? " : '" + dataStr + "'" : "");
- }
- break;
- case Asn1Tag.OBJECT_IDENTIFIER:
- Oid xoid = new Oid();
- oid = xoid.Decode(data);
- oidName = xoid.GetOidName(oid);
- if ((mask & TagTextMask.SHOW_OFFSET) != 0)
- {
- nodeStr += offsetStr;
- }
- nodeStr += " " + TagName;
- nodeStr += " : " + oidName;
- if ((mask & TagTextMask.SHOW_DATA) != 0)
- {
- nodeStr += ((oid.Length > 0) ? " : '" + oid + "'" : "");
- }
- break;
- case Asn1Tag.RELATIVE_OID:
- RelativeOid roid = new RelativeOid();
- oid = roid.Decode(data);
- oidName = "";
- if ((mask & TagTextMask.SHOW_OFFSET) != 0)
- {
- nodeStr += offsetStr;
- }
- nodeStr += " " + TagName;
- nodeStr += " : " + oidName;
- if ((mask & TagTextMask.SHOW_DATA) != 0)
- {
- nodeStr += ((oid.Length > 0) ? " : '" + oid + "'" : "");
- }
- break;
- case Asn1Tag.PRINTABLE_STRING:
- case Asn1Tag.IA5_STRING:
- case Asn1Tag.UNIVERSAL_STRING:
- case Asn1Tag.VISIBLE_STRING:
- case Asn1Tag.NUMERIC_STRING:
- case Asn1Tag.UTC_TIME:
- case Asn1Tag.UTF8_STRING:
- case Asn1Tag.BMPSTRING:
- case Asn1Tag.GENERAL_STRING:
- case Asn1Tag.GENERALIZED_TIME:
- if ((mask & TagTextMask.SHOW_OFFSET) != 0)
- {
- nodeStr += offsetStr;
- }
- nodeStr += " " + TagName;
- if ((mask & TagTextMask.SHOW_DATA) != 0)
- {
- if (tag == Asn1Tag.UTF8_STRING)
- {
- UTF8Encoding unicode = new UTF8Encoding();
- dataStr = unicode.GetString(data);
- }
- else
- {
- dataStr = Asn1Util.BytesToString(data);
- }
- nodeStr += ((dataStr.Length > 0) ? " : '" + dataStr + "'" : "");
- }
- break;
- case Asn1Tag.INTEGER:
- if ((mask & TagTextMask.SHOW_OFFSET) != 0)
- {
- nodeStr += offsetStr;
- }
- nodeStr += " " + TagName;
- if ((mask & TagTextMask.SHOW_DATA) != 0)
- {
- if (data != null && dataLength < 8)
- {
- dataStr = Asn1Util.BytesToLong(data).ToString();
- }
- else
- {
- dataStr = Asn1Util.ToHexString(data);
- }
- nodeStr += ((dataStr.Length > 0) ? " : '" + dataStr + "'" : "");
- }
- break;
- default:
- if ((mask & TagTextMask.SHOW_OFFSET) != 0)
- {
- nodeStr += offsetStr;
- }
- nodeStr += " " + TagName;
- if ((mask & TagTextMask.SHOW_DATA) != 0)
- {
- if ((tag & Asn1Tag.TAG_MASK) == 6) // Visible string for certificate
- {
- dataStr = Asn1Util.BytesToString(data);
- }
- else
- {
- dataStr = Asn1Util.ToHexString(data);
- }
- nodeStr += ((dataStr.Length > 0) ? " : '" + dataStr + "'" : "");
- }
- break;
- };
- if ((mask & TagTextMask.SHOW_PATH) != 0)
- {
- nodeStr = "(" + path + ") " + nodeStr;
- }
- return nodeStr;
- }
-
- /// <summary>
- /// Get data length. Not included the unused bits byte for BITSTRING.
- /// </summary>
- public long DataLength
- {
- get
- {
- return dataLength;
- }
- }
-
- /// <summary>
- /// Get the length field bytes.
- /// </summary>
- public long LengthFieldBytes
- {
- get
- {
- return lengthFieldBytes;
- }
- }
-
- /// <summary>
- /// Get/Set node data by byte[], the data length field content and all the
- /// node in the parent chain will be adjusted.
- /// <br></br>
- /// It return all the child data for constructed node.
- /// </summary>
- public byte[] Data
- {
- get
- {
- MemoryStream xdata = new MemoryStream();
- long nodeCount = ChildNodeCount;
- if (nodeCount == 0)
- {
- if (data != null)
- {
- xdata.Write(data, 0, data.Length);
- }
- }
- else
- {
- Asn1Node tempNode;
- for (int i = 0; i < nodeCount; i++)
- {
- tempNode = GetChildNode(i);
- tempNode.SaveData(xdata);
- }
- }
- byte[] tmpData = new byte[xdata.Length];
- xdata.Position = 0;
- xdata.Read(tmpData, 0, (int)xdata.Length);
- xdata.Close();
- return tmpData;
- }
- set
- {
- SetData(value);
- }
- }
-
- /// <summary>
- /// Get the deepness of the node.
- /// </summary>
- public long Deepness
- {
- get
- {
- return deepness;
- }
- }
-
- /// <summary>
- /// Get data offset.
- /// </summary>
- public long DataOffset
- {
- get
- {
- return dataOffset;
- }
- }
-
- /// <summary>
- /// Get unused bits for BITSTRING.
- /// </summary>
- public byte UnusedBits
- {
- get
- {
- return unusedBits;
- }
- set
- {
- unusedBits = value;
- }
- }
-
-
- /// <summary>
- /// Get descendant node by node path.
- /// </summary>
- /// <param name="nodePath">relative node path that refer to current node.</param>
- /// <returns></returns>
- public Asn1Node GetDescendantNodeByPath(string nodePath)
- {
- Asn1Node retval = this;
- if (nodePath == null) return retval;
- nodePath = nodePath.TrimEnd().TrimStart();
- if (nodePath.Length < 1) return retval;
- string[] route = nodePath.Split('/');
- try
- {
- for (int i = 1; i < route.Length; i++)
- {
- retval = retval.GetChildNode(Convert.ToInt32(route[i]));
- }
- }
- catch
- {
- retval = null;
- }
- return retval;
- }
-
- /// <summary>
- /// Get node by OID.
- /// </summary>
- /// <param name="oid">OID.</param>
- /// <param name="startNode">Starting node.</param>
- /// <returns>Null or Asn1Node.</returns>
- static public Asn1Node GetDecendantNodeByOid(string oid, Asn1Node startNode)
- {
- Asn1Node retval = null;
- Oid xoid = new Oid();
- for (int i = 0; i < startNode.ChildNodeCount; i++)
- {
- Asn1Node childNode = startNode.GetChildNode(i);
- int tmpTag = childNode.tag & Asn1Tag.TAG_MASK;
- if (tmpTag == Asn1Tag.OBJECT_IDENTIFIER)
- {
- if (oid == xoid.Decode(childNode.Data))
- {
- retval = childNode;
- break;
- }
- }
- retval = GetDecendantNodeByOid(oid, childNode);
- if (retval != null) break;
- }
- return retval;
- }
-
- /// <summary>
- /// Constant of tag field length.
- /// </summary>
- public const int TagLength = 1;
-
- /// <summary>
- /// Constant of unused bits field length.
- /// </summary>
- public const int BitStringUnusedFiledLength = 1;
-
- /// <summary>
- /// Tag text generation mask definition.
- /// </summary>
- public class TagTextMask
- {
- /// <summary>
- /// Show offset.
- /// </summary>
- public const uint SHOW_OFFSET = 0x01;
-
- /// <summary>
- /// Show decoded data.
- /// </summary>
- public const uint SHOW_DATA = 0x02;
-
- /// <summary>
- /// Show offset in hex format.
- /// </summary>
- public const uint USE_HEX_OFFSET = 0x04;
-
- /// <summary>
- /// Show tag.
- /// </summary>
- public const uint SHOW_TAG_NUMBER = 0x08;
-
- /// <summary>
- /// Show node path.
- /// </summary>
- public const uint SHOW_PATH = 0x10;
- }
-
- /// <summary>
- /// Set/Get requireRecalculatePar. RecalculateTreePar function will not do anything
- /// if it is set to false.
- /// </summary>
- protected bool RequireRecalculatePar
- {
- get
- {
- return requireRecalculatePar;
- }
- set
- {
- requireRecalculatePar = value;
- }
- }
-
- //ProtectedMembers
-
- /// <summary>
- /// Find root node and recalculate entire tree length field,
- /// path, offset and deepness.
- /// </summary>
- protected void RecalculateTreePar()
- {
- if (!requireRecalculatePar) return;
- Asn1Node rootNode;
- for (rootNode = this; rootNode.ParentNode != null;)
- {
- rootNode = rootNode.ParentNode;
- }
- ResetBranchDataLength(rootNode);
- rootNode.dataOffset = 0;
- rootNode.deepness = 0;
- long subOffset = rootNode.dataOffset + TagLength + rootNode.lengthFieldBytes;
- ResetChildNodePar(rootNode, subOffset);
- }
-
- /// <summary>
- /// Recursively set all the node data length.
- /// </summary>
- /// <param name="node"></param>
- /// <returns>node data length.</returns>
- protected static long ResetBranchDataLength(Asn1Node node)
- {
- long retval = 0;
- long childDataLength = 0;
- if (node.ChildNodeCount < 1)
- {
- if (node.data != null)
- childDataLength += node.data.Length;
- }
- else
- {
- for (int i = 0; i < node.ChildNodeCount; i++)
- {
- childDataLength += ResetBranchDataLength(node.GetChildNode(i));
- }
- }
- node.dataLength = childDataLength;
- if (node.tag == Asn1Tag.BIT_STRING)
- node.dataLength += BitStringUnusedFiledLength;
- ResetDataLengthFieldWidth(node);
- retval = node.dataLength + TagLength + node.lengthFieldBytes;
- return retval;
- }
-
- /// <summary>
- /// Encode the node data length field and set lengthFieldBytes and dataLength.
- /// </summary>
- /// <param name="node">The node needs to be reset.</param>
- protected static void ResetDataLengthFieldWidth(Asn1Node node)
- {
- MemoryStream tempStream = new MemoryStream();
- Asn1Util.DERLengthEncode(tempStream, (ulong)node.dataLength);
- node.lengthFieldBytes = tempStream.Length;
- tempStream.Close();
- }
-
- /// <summary>
- /// Recursively set all the child parameters, except dataLength.
- /// dataLength is set by ResetBranchDataLength.
- /// </summary>
- /// <param name="xNode">Starting node.</param>
- /// <param name="subOffset">Starting node offset.</param>
- protected void ResetChildNodePar(Asn1Node xNode, long subOffset)
- {
- int i;
- if (xNode.tag == Asn1Tag.BIT_STRING)
- {
- subOffset++;
- }
- Asn1Node tempNode;
- for (i = 0; i < xNode.ChildNodeCount; i++)
- {
- tempNode = xNode.GetChildNode(i);
- tempNode.parentNode = xNode;
- tempNode.dataOffset = subOffset;
- tempNode.deepness = xNode.deepness + 1;
- tempNode.path = xNode.path + '/' + i.ToString();
- subOffset += TagLength + tempNode.lengthFieldBytes;
- ResetChildNodePar(tempNode, subOffset);
- subOffset += tempNode.dataLength;
- }
- }
-
- /// <summary>
- /// Generate all the child text from childNodeList.
- /// </summary>
- /// <param name="startNode">Starting node.</param>
- /// <param name="lineLen">Line length.</param>
- /// <returns>Text string.</returns>
- protected string GetListStr(Asn1Node startNode, int lineLen)
- {
- string nodeStr = "";
- int i;
- Asn1Node tempNode;
- for (i = 0; i < childNodeList.Count; i++)
- {
- tempNode = (Asn1Node)childNodeList[i];
- nodeStr += tempNode.GetText(startNode, lineLen);
- }
- return nodeStr;
- }
-
- /// <summary>
- /// Generate the node indent string.
- /// </summary>
- /// <param name="startNode">The node.</param>
- /// <returns>Text string.</returns>
- protected string GetIndentStr(Asn1Node startNode)
- {
- string retval = "";
- long startLen = 0;
- if (startNode != null)
- {
- startLen = startNode.Deepness;
- }
- for (long i = 0; i < deepness - startLen; i++)
- {
- retval += " ";
- }
- return retval;
- }
-
- /// <summary>
- /// Decode ASN.1 encoded node Stream data.
- /// </summary>
- /// <param name="xdata">Stream data.</param>
- /// <returns>true:Succeed, false:Failed.</returns>
- protected bool GeneralDecode(Stream xdata)
- {
- long nodeMaxLen = xdata.Length - xdata.Position;
- tag = (byte)xdata.ReadByte();
- long start = xdata.Position;
- dataLength = Asn1Util.DerLengthDecode(xdata, ref isIndefiniteLength);
-
- if (AreTagsOk())
- {
- if (isIndefiniteLength)
- {
- return GeneralDecodeIndefiniteLength(xdata, nodeMaxLen - k_IndefiniteLengthFooterSize);
- }
- else
- {
- return GeneralDecodeKnownLengthWithChecks(xdata, start, nodeMaxLen);
- }
- }
- else
- {
- return false;
- }
- }
-
- private bool AreTagsOk()
- {
- if (ParentNode == null || ((ParentNode.tag & Asn1TagClasses.CONSTRUCTED) == 0))
- {
- if ((tag & Asn1Tag.TAG_MASK) <= 0 || (tag & Asn1Tag.TAG_MASK) > 0x1E)
- {
- return false;
- }
- }
-
- return true;
- }
-
- private bool GeneralDecodeKnownLengthWithChecks(Stream xdata, long start, long nodeMaxLen)
- {
- if (IsGeneralStreamLengthOk(xdata, start, nodeMaxLen))
- {
- return GeneralDecodeKnownLength(xdata);
- }
-
- return false;
- }
-
- private bool IsGeneralStreamLengthOk(Stream xdata, long start, long nodeMaxLen)
- {
- if (dataLength >= 0)
- {
- lengthFieldBytes = xdata.Position - start;
-
- if (nodeMaxLen >= (dataLength + TagLength + lengthFieldBytes))
- {
- return true;
- }
- }
-
- return false;
- }
-
- private bool GeneralDecodeKnownLength(Stream xdata)
- {
- if (tag == Asn1Tag.BIT_STRING)
- {
- // First byte of BIT_STRING is unused bits.
- // BIT_STRING data does not include this byte.
-
- // Fixed by Gustaf Bj�rklund.
- if (dataLength < 1)
- {
- return false;
- }
-
- unusedBits = (byte)xdata.ReadByte();
- ReadStreamDataDefiniteLength(xdata, (int)(dataLength - 1));
- }
- else
- {
- ReadStreamDataDefiniteLength(xdata, (int)(dataLength));
- }
-
- return true;
- }
-
- private void ReadStreamDataDefiniteLength(Stream xdata, int length)
- {
- data = new byte[length];
- xdata.Read(data, 0, (int)(length));
- }
-
- private bool GeneralDecodeIndefiniteLength(Stream xdata, long nodeMaxLen)
- {
- if (tag == Asn1Tag.BIT_STRING)
- {
- unusedBits = (byte)xdata.ReadByte();
- nodeMaxLen--;
- }
-
- return ReadStreamDataIndefiniteLength(xdata, nodeMaxLen);
- }
-
- bool ReadStreamDataIndefiniteLength(Stream xdata, long nodeMaxLen)
- {
- var streamPosition = xdata.Position;
-
- long contentLength = MeasureContentLength(xdata);
-
- if (contentLength != k_InvalidIndeterminateContentLength && contentLength <= nodeMaxLen)
- {
- ReadMeasuredLengthDataFromStart(xdata, streamPosition, contentLength);
- return true;
- }
- else
- {
- return false;
- }
- }
-
- long MeasureContentLength(Stream xdata)
- {
- long contentLength = 0;
- bool firstEocByteFound = false;
- bool foundEoc = false;
-
- while (!foundEoc)
- {
- var currentByte = xdata.ReadByte();
-
- if (currentByte == k_EndOfStream)
- {
- foundEoc = true;
- contentLength = k_InvalidIndeterminateContentLength;
- }
- else if (currentByte == Asn1Tag.TAG_END_OF_CONTENTS)
- {
- if (firstEocByteFound)
- {
- foundEoc = true;
- }
- else
- {
- firstEocByteFound = true;
- }
- }
- else
- {
- if (firstEocByteFound)
- {
- firstEocByteFound = false;
- contentLength++;
- }
-
- contentLength++;
- }
- }
-
- return contentLength;
- }
-
- void ReadMeasuredLengthDataFromStart(Stream xdata, long startPosition, long length)
- {
- xdata.Seek(startPosition, SeekOrigin.Begin);
-
- data = new byte[length];
- xdata.Read(data, 0, (int)(length));
- }
-
- /// <summary>
- /// Decode ASN.1 encoded complex data type Stream data.
- /// </summary>
- /// <param name="xdata">Stream data.</param>
- /// <returns>true:Succeed, false:Failed.</returns>
- protected bool ListDecode(Stream xdata)
- {
- bool retval = false;
- long originalPosition = xdata.Position;
-
- try
- {
- tag = (byte)xdata.ReadByte();
- long start = xdata.Position;
- dataLength = Asn1Util.DerLengthDecode(xdata, ref isIndefiniteLength);
-
- long childNodeMaxLen = xdata.Length - xdata.Position;
-
- if (isIndefiniteLength)
- {
- retval = ListDecodeIndefiniteLength(xdata, start, childNodeMaxLen - k_IndefiniteLengthFooterSize);
- }
- else
- {
- retval = ListDecodeKnownLengthWithChecks(xdata, start, childNodeMaxLen);
- }
- }
- finally
- {
- if (!retval)
- {
- xdata.Position = originalPosition;
- ClearAll();
- }
- }
- return retval;
- }
-
- private bool ListDecodeKnownLengthWithChecks(Stream xdata, long start, long childNodeMaxLen)
- {
- if (IsListStreamLengthOk(xdata, childNodeMaxLen))
- {
- return ListDecodeKnownLength(xdata, start);
- }
-
- return false;
- }
-
- private bool IsListStreamLengthOk(Stream xdata, long childNodeMaxLen)
- {
- return (dataLength >= 0 && childNodeMaxLen >= dataLength);
- }
-
- private bool ListDecodeKnownLength(Stream xdata, long start)
- {
- long offset = CalculateListEncodeFieldBytesAndOffset(xdata, start);
-
- HandleBitStringTag(xdata, ref offset);
-
- if (dataLength > 0)
- {
- return ListDecodeKnownLengthInternal(xdata, offset);
- }
-
- return false;
- }
-
- private long CalculateListEncodeFieldBytesAndOffset(Stream xdata, long start)
- {
- lengthFieldBytes = xdata.Position - start;
-
- return dataOffset + TagLength + lengthFieldBytes;
- }
-
- bool HandleBitStringTag(Stream xdata, ref long offset)
- {
- if (tag == Asn1Tag.BIT_STRING)
- {
- // First byte of BIT_STRING is unused bits.
- // BIT_STRING data does not include this byte.
- unusedBits = (byte)xdata.ReadByte();
- dataLength--;
- offset++;
-
- return true;
- }
-
- return false;
- }
-
- private bool ListDecodeKnownLengthInternal(Stream xdata, long offset)
- {
- Stream secData = CreateAndPrepareListDecodeMemoryStreamKnownLength(xdata);
-
- return ListDecodeChildNodesWithKnownLength(secData, offset);
- }
-
- private Stream CreateAndPrepareListDecodeMemoryStreamKnownLength(Stream xdata)
- {
- Stream secData = new MemoryStream((int)dataLength);
- byte[] secByte = new byte[dataLength];
-
- xdata.Read(secByte, 0, (int)(dataLength));
-
- if (tag == Asn1Tag.BIT_STRING)
- {
- dataLength++;
- }
-
- secData.Write(secByte, 0, secByte.Length);
- secData.Position = 0;
-
- return secData;
- }
-
- private bool ListDecodeChildNodesWithKnownLength(Stream secData, long offset)
- {
- while (secData.Position < secData.Length)
- {
- if (!CreateAndAddChildNode(secData, ref offset))
- {
- return false;
- }
- }
-
- return true;
- }
-
- private bool CreateAndAddChildNode(Stream secData, ref long offset)
- {
- var node = new Asn1Node(this, offset);
- node.parseEncapsulatedData = this.parseEncapsulatedData;
- long start = secData.Position;
-
- if (!node.InternalLoadData(secData))
- {
- return false;
- }
- AddChild(node);
-
- offset += secData.Position - start;
-
- return true;
- }
-
- private bool ListDecodeIndefiniteLength(Stream xdata, long start, long childNodeMaxLen)
- {
- long offset = CalculateListEncodeFieldBytesAndOffset(xdata, start);
-
- if (HandleBitStringTag(xdata, ref offset))
- {
- childNodeMaxLen--;
- }
-
- return ListDecodeIndefiniteLengthInternal(xdata, offset, childNodeMaxLen);
- }
-
- bool ListDecodeIndefiniteLengthInternal(Stream xdata, long offset, long childNodeMaxLen)
- {
- bool doneReading = false;
-
- while (!doneReading)
- {
- var oldOffset = offset;
- doneReading = ReadNextChildNodeOrEndFooterOfIndefiniteListClearIfInvalid(xdata, ref offset, childNodeMaxLen);
- childNodeMaxLen -= (offset - oldOffset);
- }
-
- return ChildNodeCount > 0;
- }
-
- bool ReadNextChildNodeOrEndFooterOfIndefiniteListClearIfInvalid(Stream xdata, ref long offset, long childNodeMaxLen)
- {
- bool doneReading;
- var byteChecks = DetectEndOfIndefiniteListContents(xdata);
-
- if (byteChecks == Asn1EndOfIndefiniteLengthNodeType.NotEnd)
- {
- doneReading = !ReadNextChildNodeOfIndefiniteListClearIfInvalid(xdata, ref offset, childNodeMaxLen);
- }
- else
- {
- if (byteChecks == Asn1EndOfIndefiniteLengthNodeType.EndOfStream && ChildNodeCount > 0)
- {
- //DEVELOPERS' NOTE:
- //End of Stream hit parsing an Indeterminate Length List Node.
- //This Indeterminate Length List Node is a false flag that just happens to have initial bytes matching the pattern of such a node.
-
- ClearAll();
- }
-
- doneReading = true;
- }
-
- return doneReading;
- }
-
- Asn1EndOfIndefiniteLengthNodeType DetectEndOfIndefiniteListContents(Stream xdata)
- {
- var tagByte = xdata.ReadByte();
- if (tagByte != k_EndOfStream)
- {
- var lengthByte = xdata.ReadByte();
-
- if (lengthByte != k_EndOfStream)
- {
- if (tagByte == Asn1Tag.TAG_END_OF_CONTENTS && lengthByte == Asn1Tag.TAG_END_OF_CONTENTS)
- {
- return Asn1EndOfIndefiniteLengthNodeType.EndOfNodeFooter;
- }
- else
- {
- return Asn1EndOfIndefiniteLengthNodeType.NotEnd;
- }
- }
- }
- return Asn1EndOfIndefiniteLengthNodeType.EndOfStream;
- }
-
- bool ReadNextChildNodeOfIndefiniteListClearIfInvalid(Stream xdata, ref long offset, long childNodeMaxLen)
- {
- xdata.Position -= k_IndefiniteLengthFooterSize;
-
- bool validChildNode = false;
- if (CreateAndAddChildNode(xdata, ref offset))
- {
- validChildNode = GetLastChild().DataLength < childNodeMaxLen;
- }
-
- if (ChildNodeCount > 0 && !validChildNode)
- {
- //DEVELOPERS' NOTE:
- //Invalid sequential child Asn1Node found in an Indeterminate Length List Node.
- //This Indeterminate Length List Node is a false flag that just happens to have initial bytes matching the pattern of such a node.
-
- ClearAll();
- }
-
- return validChildNode;
- }
-
- /// <summary>
- /// Set the node data and recalculate the entire tree parameters.
- /// </summary>
- /// <param name="xdata">byte[] data.</param>
- protected void SetData(byte[] xdata)
- {
- if (childNodeList.Count > 0)
- {
- throw new Exception("Constructed node can't hold simple data.");
- }
- else
- {
- data = xdata;
- if (data != null)
- {
- dataLength = data.Length;
- }
- else
- {
- dataLength = 0;
- }
-
- RecalculateTreePar();
- }
- }
-
- /// <summary>
- /// Load data from Stream. Start from current position.
- /// </summary>
- /// <param name="xdata">Stream</param>
- /// <returns>true:Succeed; false:failed.</returns>
- protected bool InternalLoadData(Stream xdata)
- {
- bool retval = true;
- ClearAll();
- byte xtag;
-
- long curPosition = xdata.Position;
- xtag = (byte)xdata.ReadByte();
-
- xdata.Position = curPosition;
- int maskedTag = xtag & Asn1Tag.TAG_MASK;
- if (((xtag & Asn1TagClasses.CONSTRUCTED) != 0)
- || (parseEncapsulatedData
- && ((maskedTag == Asn1Tag.BIT_STRING)
- || (maskedTag == Asn1Tag.EXTERNAL)
- || (maskedTag == Asn1Tag.GENERAL_STRING)
- || (maskedTag == Asn1Tag.GENERALIZED_TIME)
- || (maskedTag == Asn1Tag.GRAPHIC_STRING)
- || (maskedTag == Asn1Tag.IA5_STRING)
- || (maskedTag == Asn1Tag.OCTET_STRING)
- || (maskedTag == Asn1Tag.PRINTABLE_STRING)
- || (maskedTag == Asn1Tag.SEQUENCE)
- || (maskedTag == Asn1Tag.SET)
- || (maskedTag == Asn1Tag.T61_STRING)
- || (maskedTag == Asn1Tag.UNIVERSAL_STRING)
- || (maskedTag == Asn1Tag.UTF8_STRING)
- || (maskedTag == Asn1Tag.VIDEOTEXT_STRING)
- || (maskedTag == Asn1Tag.VISIBLE_STRING)))
- )
- {
- if (!ListDecode(xdata))
- {
- if (!GeneralDecode(xdata))
- {
- retval = false;
- }
- }
- }
- else
- {
- if (!GeneralDecode(xdata)) retval = false;
- }
-
- return retval;
- }
-
- /// <summary>
- /// Get/Set parseEncapsulatedData. This property will be inherited by the
- /// child nodes when loading data.
- /// </summary>
- public bool ParseEncapsulatedData
- {
- get
- {
- return parseEncapsulatedData;
- }
- set
- {
- if (parseEncapsulatedData == value) return;
- byte[] tmpData = Data;
- parseEncapsulatedData = value;
- ClearAll();
- if ((tag & Asn1TagClasses.CONSTRUCTED) != 0 || parseEncapsulatedData)
- {
- MemoryStream ms = new MemoryStream(tmpData);
- ms.Position = 0;
- bool isLoaded = true;
- while (ms.Position < ms.Length)
- {
- Asn1Node tempNode = new Asn1Node();
- tempNode.ParseEncapsulatedData = parseEncapsulatedData;
- if (!tempNode.LoadData(ms))
- {
- ClearAll();
- isLoaded = false;
- break;
- }
- AddChild(tempNode);
- }
- if (!isLoaded)
- {
- Data = tmpData;
- }
- }
- else
- {
- Data = tmpData;
- }
- }
- }
- }
- }
|