using System.IO; using System; namespace Unosquare.Swan.Networking.Ldap { /// /// This class provides LBER decoding routines for ASN.1 Types. LBER is a /// subset of BER as described in the following taken from 5.1 of RFC 2251: /// 5.1. Mapping Onto BER-based Transport Services /// The protocol elements of Ldap are encoded for exchange using the /// Basic Encoding Rules (BER) [11] of ASN.1 [3]. However, due to the /// high overhead involved in using certain elements of the BER, the /// following additional restrictions are placed on BER-encodings of Ldap /// protocol elements: ///
  • (1) Only the definite form of length encoding will be used.
  • ///
  • (2) OCTET STRING values will be encoded in the primitive form only.
  • /// (3) If the value of a BOOLEAN type is true, the encoding MUST have /// its contents octets set to hex "FF". ///
  • /// (4) If a value of a type is its default value, it MUST be absent. /// Only some BOOLEAN and INTEGER types have default values in this /// protocol definition. /// These restrictions do not apply to ASN.1 types encapsulated inside of /// OCTET STRING values, such as attribute values, unless otherwise /// noted. ///
  • /// [3] ITU-T Rec. X.680, "Abstract Syntax Notation One (ASN.1) - /// Specification of Basic Notation", 1994. /// [11] ITU-T Rec. X.690, "Specification of ASN.1 encoding rules: Basic, /// Canonical, and Distinguished Encoding Rules", 1994. ///
    internal static class LberDecoder { /// /// Decode an LBER encoded value into an Asn1Object from an InputStream. /// This method also returns the total length of this encoded /// Asn1Object (length of type + length of length + length of content) /// in the parameter len. This information is helpful when decoding /// structured types. /// /// The stream. /// The length. /// /// Decoded Asn1Obect. /// /// Unknown tag. public static Asn1Object Decode(Stream stream, Int32[] len) { Asn1Identifier asn1Id = new Asn1Identifier(stream); Asn1Length asn1Len = new Asn1Length(stream); Int32 length = asn1Len.Length; len[0] = asn1Id.EncodedLength + asn1Len.EncodedLength + length; if(asn1Id.Universal == false) { return new Asn1Tagged(stream, length, (Asn1Identifier)asn1Id.Clone()); } switch(asn1Id.Tag) { case Asn1Sequence.Tag: return new Asn1Sequence(stream, length); case Asn1Set.Tag: return new Asn1Set(stream, length); case Asn1Boolean.Tag: return new Asn1Boolean(stream, length); case Asn1Integer.Tag: return new Asn1Integer(stream, length); case Asn1OctetString.Tag: return new Asn1OctetString(stream, length); case Asn1Enumerated.Tag: return new Asn1Enumerated(stream, length); case Asn1Null.Tag: return new Asn1Null(); // has no content to decode. default: throw new EndOfStreamException("Unknown tag"); } } /// /// Decode a boolean directly from a stream. /// /// The stream. /// Length in bytes. /// /// Decoded boolean object. /// /// LBER: BOOLEAN: decode error: EOF. public static Boolean DecodeBoolean(Stream stream, Int32 len) { SByte[] lber = new SByte[len]; if(stream.ReadInput(ref lber, 0, lber.Length) != len) { throw new EndOfStreamException("LBER: BOOLEAN: decode error: EOF"); } return lber[0] != 0x00; } /// /// Decode a Numeric type directly from a stream. Decodes INTEGER /// and ENUMERATED types. /// /// The stream. /// Length in bytes. /// /// Decoded numeric object. /// /// /// LBER: NUMERIC: decode error: EOF /// or /// LBER: NUMERIC: decode error: EOF. /// public static Int64 DecodeNumeric(Stream stream, Int32 len) { Int64 l = 0; Int32 r = stream.ReadByte(); if(r < 0) { throw new EndOfStreamException("LBER: NUMERIC: decode error: EOF"); } if((r & 0x80) != 0) { // check for negative number l = -1; } #pragma warning disable CS0675 // Bitweiser OR-Operator, der bei einem signaturerweiterten Operanden verwendet wurde. l = (l << 8) | r; #pragma warning restore CS0675 // Bitweiser OR-Operator, der bei einem signaturerweiterten Operanden verwendet wurde. for(Int32 i = 1; i < len; i++) { r = stream.ReadByte(); if(r < 0) { throw new EndOfStreamException("LBER: NUMERIC: decode error: EOF"); } #pragma warning disable CS0675 // Bitweiser OR-Operator, der bei einem signaturerweiterten Operanden verwendet wurde. l = (l << 8) | r; #pragma warning restore CS0675 // Bitweiser OR-Operator, der bei einem signaturerweiterten Operanden verwendet wurde. } return l; } /// /// Decode an OctetString directly from a stream. /// /// The stream. /// Length in bytes. /// Decoded octet. public static Object DecodeOctetString(Stream stream, Int32 len) { SByte[] octets = new SByte[len]; Int32 totalLen = 0; while(totalLen < len) { // Make sure we have read all the data totalLen += stream.ReadInput(ref octets, totalLen, len - totalLen); } return octets; } } }