/// <summary> /// Assert end of Constructed type of node, i.e. SEQUENCE, SET. Then move to next node. /// </summary> /// <param name="reader">BerReader instance.</param> /// <param name="level">Depth of node in ASN.1 structure.</param> /// <param name="type">Type of given node to assert.</param> private static void AssertReadEnd(BerReader reader, int level, Asn1Type type) { Assert.AreEqual(level, reader.Depth, "Depth"); Assert.AreEqual(Asn1NodeType.ConstructedEnd, reader.CurrentNode.NodeType, "Node Tag"); Assert.AreEqual(type, reader.CurrentNode.Identifier.Tag, "Tag"); Assert.AreEqual(0, reader.CurrentNode.Length, "Length"); Assert.IsTrue(reader.CurrentNode.IsConstructed, "IsConstructed"); Assert.IsFalse(reader.CurrentNode.NodeType == Asn1NodeType.DocumentEnd, "EndOfDocument"); reader.Read(); }
public void DoesNotTouchStreamBeforeRead() { // Given var memoryStream = new MemoryStream(); // When var berReader = new BerReader(memoryStream); // Then Assert.AreEqual(0, memoryStream.Position); }
public void DisposeTests() { // Given // Example taken from: http://msdn.microsoft.com/en-us/library/bb540809%28v=vs.85%29.aspx const string example = @" 06 09 ; OBJECT_ID (9 Bytes) | 2b 06 01 04 01 82 37 15 14 ; 1.3.6.1.4.1.311.21.20 "; var encoded = Helpers.GetExampleBytes(example); // Given var memoryStream = new MemoryStream(encoded); // When using (var berReader = new BerReader(memoryStream)) { // Then Assert.AreEqual(Asn1NodeType.DocumentStart, berReader.CurrentNode.NodeType); } bool objectDisposed = false; try { //should throw ObjectDisposedException var position = memoryStream.Position; } catch (ObjectDisposedException) { objectDisposed = true; } Assert.IsTrue(objectDisposed); // Given memoryStream = new MemoryStream(encoded); // When using (var berReader = new BerReader(memoryStream, true)) { // Then Assert.AreEqual(Asn1NodeType.DocumentStart, berReader.CurrentNode.NodeType); } Assert.IsTrue(memoryStream.Position == 0); //should NOT throw ObjectDisposedException }
/// <summary> /// Read the value of the given node as list of children in the set. /// </summary> /// <returns>Value of the given node as list of children in the set.</returns> internal override List <Asn1ObjectBase> ReadEncodedValue() { if (this.RawContent == null) { throw new ArgumentException("Stream that contains encoded value is null."); } var content = this.RawContent; content.Seek(0, SeekOrigin.Begin); var internalReader = new BerReader(content); List <Asn1ObjectBase> children; internalReader.Read(out children); return(children); }
/// <summary> /// Load ASN.1 object in form of a stream, parse it and display its structure. /// </summary> /// <param name="asn1Content">ASN.1 object to parse.</param> public void LoadContent(Stream asn1Content) { // clear any existing nodes Nodes.Clear(); // use parser to get the structure using (var reader = new BerReader(asn1Content)) { var rootNode = new InternalNode(); try { // read whole object. This may fail if there is no valid ASN.1 object in the stream. rootNode = reader.ReadToEnd(ReadContent); } catch (Exception ex) { // something went wrong when reading file. Possibly it was not an ASN.1 object. Trace.WriteLine(String.Format("Parsing exception: {0}", ex)); var safetyNode = new Asn1TreeNode(null, "Invalid ASN.1 structure."); Nodes.Add(safetyNode); } // reader does not parse encapsulated data. Do it manually. foreach (InternalNode internalNode in rootNode.ChildNodes) { // This will enrich list of nodes with additional nodes parsed out of values of Primitive ASN.1 nodes if (EncapsulatedDataParsing) { ParseEncapsulatedData(internalNode); } // build tree from list of ASN.1 nodes var rootTreeNode = new Asn1TreeNode(internalNode); MakeTreeNode(rootTreeNode, internalNode, 1, EncapsulatedDataParsing); Nodes.Add(rootTreeNode); } } // expand tree ExpandAll(); SelectedNode = Nodes[0]; }
/// <summary> /// Assert Primary type of node. Also read the value of the node and assert with given value. Then move to next node. /// </summary> /// <param name="reader">BerReader instance.</param> /// <param name="level">Depth of node in ASN.1 structure.</param> /// <param name="type">Type of given node to assert.</param> /// <param name="length">Length of given node to assert.</param> /// <param name="value">Value of the node to assert.</param> private static void AssertReadPri(BerReader reader, int level, Asn1Type type, int length, object value) { Assert.AreEqual(level, reader.Depth, "Depth"); Assert.AreEqual(Asn1NodeType.Primitive, reader.CurrentNode.NodeType, "Node Tag"); Assert.AreEqual(type, reader.CurrentNode.Identifier.Tag, "Tag"); Assert.AreEqual(length, reader.CurrentNode.Length, "Length"); Assert.IsFalse(reader.CurrentNode.IsConstructed, "IsConstructed"); Assert.IsFalse(reader.CurrentNode.NodeType == Asn1NodeType.DocumentEnd, "EndOfDocument"); reader.CurrentNode.RawValue = reader.ReadContentAsBuffer(); switch (reader.CurrentNode.Identifier.Tag) { case Asn1Type.ObjectIdentifier: Assert.AreEqual(value, reader.CurrentNode.ReadContentAsObjectIdentifier()); break; case Asn1Type.PrintableString: case Asn1Type.Ia5String: case Asn1Type.Utf8String: Assert.AreEqual(value, reader.CurrentNode.ReadContentAsString()); break; case Asn1Type.GeneralizedTime: case Asn1Type.UtcTime: Assert.AreEqual(value, reader.CurrentNode.ReadConventAsDateTimeOffset()); break; case Asn1Type.Integer: Assert.AreEqual(value, reader.CurrentNode.ReadContentAsBigInteger()); break; case Asn1Type.Boolean: Assert.AreEqual(value, reader.CurrentNode.ReadContentAsBoolean()); break; default: Assert.AreEqual(value, reader.CurrentNode.RawValue); break; } reader.Read(); }
/// <summary> /// Method will parse value of given node for existing ASN.1 objects. /// </summary> /// <param name="innerNode">Node to parse.</param> internal static void ParseEncapsulatedData(InternalNode innerNode) { if (innerNode.NodeType != Asn1NodeType.Primitive) { return; } if (innerNode.RawValue == null) { return; // nothing to parse } // for now, only BIT STRING or OCTET STRING may contain encapsulated data if (innerNode.Identifier.Tag != Asn1Type.BitString && innerNode.Identifier.Tag != Asn1Type.OctetString) { return; } byte[] dataToParse = innerNode.RawValue; if (innerNode.Identifier.Tag == Asn1Type.BitString) { dataToParse = innerNode.ReadContentAsBitString(); } // Reader will close the stream when it is done parsing var memStream = new MemoryStream(dataToParse); using (var innerReader = new BerReader(memStream)) { try { InternalNode innerRootNode = innerReader.ReadToEnd(true); innerNode.ChildNodes.AddRange(innerRootNode.ChildNodes); } catch (Exception) { // nothing to do. Value of primitive node did not contain valid ASN.1 structure. } } }
/// <summary> /// Формирует строка со структурным представлением байтового массива в формате ASN1 /// </summary> /// <param name="baAsn1">Байтовый массив в формате ASN1</param> /// <returns>Строка с текстовым представлением байтового массива в формате ASN1</returns> public static string PrintFromAsn1(byte[] baAsn1) { var memoryStream = new MemoryStream(baAsn1); using (var berReader = new BerReader(memoryStream)) { //Формируем текстовое представление марканта try { var node = berReader.ReadToEnd().ChildNodes[0]; string result = "ASN1:"; foreach (var childNode in node.ChildNodes) { result = berReader.PrintStructure(childNode, result, 1, true); } return(result); } catch (Exception e) { throw new Exception("Invalid ASN format", e); } } }
/// <summary> /// Печатает ASN.1 структуру /// </summary> /// <param name="reader">Объект BerReader</param> /// <param name="node">Узел дерева</param> /// <param name="relativeResult">Предыдущий результат работы данного метода</param> /// <param name="depth">Глубина вложенности</param> /// <param name="dumpValues">Печатать значения</param> /// <returns>Структура ASN.1 представленная в виде строки</returns> internal static string PrintStructure(this BerReader reader, InternalNode node, string relativeResult, int depth, bool dumpValues) { var offsetAndLength = String.Format("({0},{1})", node.StartPosition.ToString(CultureInfo.InvariantCulture), node.Length.ToString(CultureInfo.InvariantCulture)); var structure = String.Format("{0} {1}", offsetAndLength, (node.Identifier.Class == Asn1Class.ContextSpecific) ? String.Format("{0} ({1})", node.Identifier.Class, (int)node.Identifier.Tag) : node.Identifier.Tag.ToString()); if (dumpValues) { if (node.NodeType == Asn1NodeType.Primitive) { string stringValue; node.RawValue = reader.ReadContentAsBuffer(node); switch (node.Identifier.Tag) { case Asn1Type.ObjectIdentifier: stringValue = node.ReadContentAsObjectIdentifier(); break; case Asn1Type.PrintableString: case Asn1Type.Ia5String: case Asn1Type.Utf8String: stringValue = node.ReadContentAsString(); break; case Asn1Type.GeneralizedTime: case Asn1Type.UtcTime: stringValue = node.ReadConventAsDateTimeOffset().ToString(); break; case Asn1Type.Integer: stringValue = node.ReadContentAsBigInteger().ToString(); break; case Asn1Type.Boolean: stringValue = node.ReadContentAsBoolean().ToString(); break; default: stringValue = node.RawValue.ToHexString(); break; } structure = string.Format("{0} : {1}", structure, stringValue); } } for (int i = 0; i < depth; i++) { structure = "\t" + structure; } string res = relativeResult + Environment.NewLine + structure; var innerdepth = (node.ChildNodes.Count > 0) ? depth + 1 : depth; foreach (var innerNode in node.ChildNodes) { res = reader.PrintStructure(innerNode, res, innerdepth, dumpValues); } return(res); }
/// <summary> /// Prints structure of given ASN.1 node. Node should be the result of ReadToEnd method called before. /// </summary> /// <param name="reader">Extended object</param> /// <param name="node">Node to print structure of.</param> /// <param name="relativeResult">Relative result of this method. Used when iterating through the structure to build on top of previous results of this method.</param> /// <param name="depth">Actual depth of parser.</param> /// <param name="dumpValues">Flag indicating if values should be printed out.</param> /// <returns>Structure of ASN.1 node as string.</returns> internal static string PrintStructure(this BerReader reader, InternalNode node, string relativeResult, int depth, bool dumpValues) { // print offset in source stream and length of ASN.1 node var offsetAndLength = String.Format("({0},{1})", node.StartPosition.ToString(CultureInfo.InvariantCulture), node.Length.ToString(CultureInfo.InvariantCulture)); // append tag name var structure = String.Format("{0} {1}", offsetAndLength, (node.Identifier.Class == Asn1Class.ContextSpecific) ? String.Format("{0} ({1})", node.Identifier.Class, (int)node.Identifier.Tag) : node.Identifier.Tag.ToString()); // append value of ASN.1 node if (dumpValues) { if (node.NodeType == Asn1NodeType.Primitive) { string stringValue; node.RawValue = reader.ReadContentAsBuffer(node); switch (node.Identifier.Tag) { case Asn1Type.ObjectIdentifier: stringValue = node.ReadContentAsObjectIdentifier(); break; case Asn1Type.PrintableString: case Asn1Type.Ia5String: case Asn1Type.Utf8String: stringValue = node.ReadContentAsString(); break; case Asn1Type.GeneralizedTime: case Asn1Type.UtcTime: stringValue = node.ReadConventAsDateTimeOffset().ToString(); break; case Asn1Type.Integer: stringValue = node.ReadContentAsBigInteger().ToString(); break; case Asn1Type.Boolean: stringValue = node.ReadContentAsBoolean().ToString(); break; default: stringValue = node.RawValue.ToHexString(); break; } structure = string.Format("{0} : {1}", structure, stringValue); } } // apply depth for (int i = 0; i < depth; i++) { structure = "\t" + structure; } // append new line string res = relativeResult + Environment.NewLine + structure; // count new depth if node has children var innerdepth = (node.ChildNodes.Count > 0) ? depth + 1 : depth; // recursively go through children and print structure of them foreach (var innerNode in node.ChildNodes) { res = reader.PrintStructure(innerNode, res, innerdepth, dumpValues); } // return result return(res); }