{"action":"created","comment":{"url":"https://api.github.com/repos/dotnet/corefx/pulls/comments/152463461","pull_request_review_id":78328950,"id":152463461,"diff_hunk":"@@ -0,0 +1,5246 @@\n+// Licensed to the .NET Foundation under one or more agreements.\n+// The .NET Foundation licenses this file to you under the MIT license.\n+// See the LICENSE file in the project root for more information.\n+\n+using System.Buffers;\n+using System.Collections.Generic;\n+using System.Diagnostics;\n+using System.Numerics;\n+using System.Runtime.InteropServices;\n+using System.Text;\n+\n+namespace System.Security.Cryptography.Asn1\n+{\n+    // Uses a masked overlay of the tag class encoding.\n+    // T-REC-X.690-201508 sec 8.1.2.2\n+    internal enum TagClass : byte\n+    {\n+        Universal = 0,\n+        Application = 0b0100_0000,\n+        ContextSpecific = 0b1000_0000,\n+        Private = 0b1100_0000,\n+    }\n+\n+    internal enum UniversalTagNumber\n+    {\n+        EndOfContents = 0,\n+        Boolean = 1,\n+        Integer = 2,\n+        BitString = 3,\n+        OctetString = 4,\n+        Null = 5,\n+        ObjectIdentifier = 6,\n+        ObjectDescriptor = 7,\n+        External = 8,\n+        InstanceOf = External,\n+        Real = 9,\n+        Enumerated = 10,\n+        Embedded = 11,\n+        UTF8String = 12,\n+        RelativeObjectIdentifier = 13,\n+        Time = 14,\n+        // 15 is reserved\n+        Sequence = 16,\n+        SequenceOf = Sequence,\n+        Set = 17,\n+        SetOf = Set,\n+        NumericString = 18,\n+        PrintableString = 19,\n+        TeletexString = 20,\n+        T61String = TeletexString,\n+        VideotexString = 21,\n+        IA5String = 22,\n+        UtcTime = 23,\n+        GeneralizedTime = 24,\n+        GraphicString = 25,\n+        VisibleString = 26,\n+        ISO646String = VisibleString,\n+        GeneralString = 27,\n+        UniversalString = 28,\n+        UnrestrictedCharacterString = 29,\n+        BMPString = 30,\n+        Date = 31,\n+        TimeOfDay = 32,\n+        DateTime = 33,\n+        Duration = 34,\n+    }\n+\n+    internal enum NamedBitListMode\n+    {\n+        /// <summary>\n+        /// In <c>BIT STRING { a(0), j(9) }</c> map <c>a | j</c> to the value <c>0x0201</c>\n+        /// </summary>\n+        NamedZeroIsOne,\n+        /// <summary>\n+        /// In <c>BIT STRING { a(0), j(9) }</c> map <c>a | j</c> to the value <c>0x4080</c>\n+        /// </summary>\n+        NamedZeroIs128LittleEndian,\n+        /// <summary>\n+        /// In <c>BIT STRING { a(0), j(9) }</c> map <c>a | j</c> to the value <c>0x8040</c>\n+        /// </summary>\n+        NamedZeroIs128BigEndian,\n+    }\n+\n+    internal struct Asn1Tag\n+    {\n+        private const byte ClassMask = 0b1100_0000;\n+        private const byte ConstructedMask = 0b0010_0000;\n+        private const byte ControlMask = ClassMask | ConstructedMask;\n+        private const byte TagNumberMask = 0b0001_1111;\n+\n+        internal static readonly Asn1Tag EndOfContents = new Asn1Tag(0);\n+        internal static readonly Asn1Tag Null = new Asn1Tag(5);\n+\n+        private readonly byte _controlFlags;\n+        private readonly int _tagValue;\n+\n+        public TagClass TagClass => (TagClass)(_controlFlags & ClassMask);\n+        public bool IsConstructed => (_controlFlags & ConstructedMask) == ConstructedMask;\n+        public int TagValue => _tagValue;\n+\n+        private Asn1Tag(byte controlFlags, int tagValue)\n+        {\n+            _controlFlags = (byte)(controlFlags & ControlMask);\n+            _tagValue = tagValue;\n+        }\n+\n+        public Asn1Tag(UniversalTagNumber universalTagNumber, bool isConstructed = false)\n+            : this(isConstructed ? ConstructedMask : (byte)0, (int)universalTagNumber)\n+        {\n+            const UniversalTagNumber ReservedIndex = (UniversalTagNumber)15;\n+\n+            if (universalTagNumber < UniversalTagNumber.EndOfContents ||\n+                universalTagNumber > UniversalTagNumber.Duration ||\n+                universalTagNumber == ReservedIndex)\n+            {\n+                throw new ArgumentOutOfRangeException(nameof(universalTagNumber), universalTagNumber, null);\n+            }\n+        }\n+\n+        public Asn1Tag(TagClass tagClass, int tagValue, bool isConstructed = false)\n+            : this((byte)((byte)tagClass | (isConstructed ? ConstructedMask : 0)), tagValue)\n+        {\n+            if (tagClass < TagClass.Universal || tagClass > TagClass.Private)\n+            {\n+                throw new ArgumentOutOfRangeException(nameof(tagClass), tagClass, null);\n+            }\n+        }\n+\n+        public Asn1Tag(byte singleByteEncoding)\n+        {\n+            Span<byte> span = stackalloc byte[1];\n+            span[0] = singleByteEncoding;\n+\n+            if (TryParse(span, out Asn1Tag parsed, out int bytesRead))\n+            {\n+                Debug.Assert(bytesRead == 1);\n+                _controlFlags = parsed._controlFlags;\n+                _tagValue = parsed._tagValue;\n+            }\n+            else\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+        }\n+\n+        public static bool TryParse(ReadOnlySpan<byte> source, out Asn1Tag tag, out int bytesRead)\n+        {\n+            tag = default(Asn1Tag);\n+            bytesRead = 0;\n+\n+            if (source.IsEmpty)\n+                return false;\n+\n+            byte first = source[bytesRead];\n+            bytesRead++;\n+            uint tagValue = (uint)(first & TagNumberMask);\n+\n+            if (tagValue == TagNumberMask)\n+            {\n+                // Multi-byte encoding\n+                // T-REC-X.690-201508 sec 8.1.2.4\n+                const byte ContinuationFlag = 0x80;\n+                const byte ValueMask = ContinuationFlag - 1;\n+\n+                tagValue = 0;\n+                byte current;\n+\n+                do\n+                {\n+                    if (source.Length <= bytesRead)\n+                    {\n+                        bytesRead = 0;\n+                        return false;\n+                    }\n+\n+                    current = source[bytesRead];\n+                    byte currentValue = (byte)(current & ValueMask);\n+                    bytesRead++;\n+\n+                    // The first byte cannot have the value 0 (T-REC-X.690-201508 sec 8.1.2.4.2.c)\n+                    if (currentValue == 0 && tagValue == 0)\n+                    {\n+                        bytesRead = 0;\n+                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                    }\n+\n+                    // If TooBigToShift is shifted left 7, the content bit shifts out.\n+                    // So any value greater than or equal to this cannot be shifted without loss.\n+                    const int TooBigToShift = 0b00000010_00000000_00000000_00000000;\n+\n+                    if (tagValue >= TooBigToShift)\n+                    {\n+                        bytesRead = 0;\n+                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                    }\n+\n+                    tagValue <<= 7;\n+                    tagValue |= currentValue;\n+                }\n+                while ((current & ContinuationFlag) == ContinuationFlag);\n+\n+                // This encoding is only valid for tag values greater than 30.\n+                // (T-REC-X.690-201508 sec 8.1.2.3, 8.1.2.4)\n+\n+                if (tagValue <= 30)\n+                {\n+                    bytesRead = 0;\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                // There's not really any ambiguity, but prevent negative numbers from showing up.\n+                if (tagValue > int.MaxValue)\n+                {\n+                    bytesRead = 0;\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+            }\n+\n+            tag = new Asn1Tag(first, (int)tagValue);\n+            return true;\n+        }\n+\n+        public int CalculateEncodedSize()\n+        {\n+            const int SevenBits = 0b0111_1111;\n+            const int FourteenBits = 0b0011_1111_1111_1111;\n+            const int TwentyOneBits = 0b0001_1111_1111_1111_1111_1111;\n+            const int TwentyEightBits = 0b0000_1111_1111_1111_1111_1111_1111_1111;\n+\n+            if (TagValue < TagNumberMask)\n+                return 1;\n+            if (TagValue <= SevenBits)\n+                return 2;\n+            if (TagValue <= FourteenBits)\n+                return 3;\n+            if (TagValue <= TwentyOneBits)\n+                return 4;\n+            if (TagValue <= TwentyEightBits)\n+                return 5;\n+\n+            return 6;\n+        }\n+\n+        public bool TryWrite(Span<byte> destination, out int bytesWritten)\n+        {\n+            int spaceRequired = CalculateEncodedSize();\n+\n+            if (destination.Length < spaceRequired)\n+            {\n+                bytesWritten = 0;\n+                return false;\n+            }\n+\n+            if (spaceRequired == 1)\n+            {\n+                byte value = (byte)(_controlFlags | TagValue);\n+                destination[0] = value;\n+                bytesWritten = 1;\n+                return true;\n+            }\n+\n+            byte firstByte = (byte)(_controlFlags | TagNumberMask);\n+            destination[0] = firstByte;\n+\n+            int remaining = TagValue;\n+            int idx = spaceRequired - 1;\n+\n+            while (remaining > 0)\n+            {\n+                int segment = remaining & 0x7F;\n+\n+                // The last byte doesn't get the marker, which we write first.\n+                if (remaining != TagValue)\n+                {\n+                    segment |= 0x80;\n+                }\n+\n+                Debug.Assert(segment <= byte.MaxValue);\n+                destination[idx] = (byte)segment;\n+                remaining >>= 7;\n+                idx--;\n+            }\n+\n+            Debug.Assert(idx == 0);\n+            bytesWritten = spaceRequired;\n+            return true;\n+        }\n+\n+        public bool Equals(Asn1Tag other)\n+        {\n+            return _controlFlags == other._controlFlags && _tagValue == other._tagValue;\n+        }\n+\n+        public override bool Equals(object obj)\n+        {\n+            if (ReferenceEquals(null, obj)) return false;\n+            return obj is Asn1Tag && Equals((Asn1Tag)obj);\n+        }\n+\n+        public override int GetHashCode()\n+        {\n+            // Most TagValue values will be in the 0-30 range,\n+            // the GetHashCode value only has collisions when TagValue is\n+            // between 2^29 and uint.MaxValue\n+            return (_controlFlags << 24) ^ _tagValue;\n+        }\n+\n+        public static bool operator ==(Asn1Tag left, Asn1Tag right)\n+        {\n+            return left.Equals(right);\n+        }\n+\n+        public static bool operator !=(Asn1Tag left, Asn1Tag right)\n+        {\n+            return !left.Equals(right);\n+        }\n+\n+        public override string ToString()\n+        {\n+            const string ConstructedPrefix = \"Constructed \";\n+            string classAndValue;\n+\n+            if (TagClass == TagClass.Universal)\n+            {\n+                classAndValue = ((UniversalTagNumber)TagValue).ToString();\n+            }\n+            else\n+            {\n+                classAndValue = TagClass + \"-\" + TagValue;\n+            }\n+\n+            if (IsConstructed)\n+            {\n+                return ConstructedPrefix + classAndValue;\n+            }\n+\n+            return classAndValue;\n+        }\n+    }\n+\n+    internal enum AsnEncodingRules\n+    {\n+        BasicEncodingRules,\n+        BER = BasicEncodingRules,\n+        CanonicalEncodingRules,\n+        CER = CanonicalEncodingRules,\n+        DistinguishedEncodingRules,\n+        DER = DistinguishedEncodingRules,\n+    }\n+\n+    internal class AsnReader\n+    {\n+        // ITU-T-REC-X.690-201508 sec 9.2\n+        internal const int MaxCERSegmentSize = 1000;\n+\n+        // ITU-T-REC-X.690-201508 sec 8.1.5 says only 0000 is legal.\n+        private const int EndOfContentsEncodedLength = 2;\n+\n+        private static readonly Text.Encoding s_utf8Encoding = new UTF8Encoding(false, true);\n+        private static readonly Text.Encoding s_bmpEncoding = new BMPEncoding();\n+        private static readonly Text.Encoding s_ia5Encoding = new IA5Encoding();\n+        private static readonly Text.Encoding s_visibleStringEncoding = new VisibleStringEncoding();\n+        private static readonly Text.Encoding s_printableStringEncoding = new PrintableStringEncoding();\n+\n+        private ReadOnlyMemory<byte> _data;\n+        private readonly AsnEncodingRules _ruleSet;\n+\n+        public bool HasData => !_data.IsEmpty;\n+\n+        public AsnReader(ReadOnlyMemory<byte> data, AsnEncodingRules ruleSet)\n+        {\n+            CheckEncodingRules(ruleSet);\n+\n+            _data = data;\n+            _ruleSet = ruleSet;\n+        }\n+\n+        public static bool TryPeekTag(ReadOnlySpan<byte> source, out Asn1Tag tag, out int bytesRead)\n+        {\n+            return Asn1Tag.TryParse(source, out tag, out bytesRead);\n+        }\n+\n+        public Asn1Tag PeekTag()\n+        {\n+            if (TryPeekTag(_data.Span, out Asn1Tag tag, out int bytesRead))\n+            {\n+                return tag;\n+            }\n+\n+            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+        }\n+\n+        private static bool TryReadLength(\n+            ReadOnlySpan<byte> source,\n+            AsnEncodingRules ruleSet,\n+            out int? length,\n+            out int bytesRead)\n+        {\n+            length = null;\n+            bytesRead = 0;\n+\n+            CheckEncodingRules(ruleSet);\n+\n+            if (source.IsEmpty)\n+                return false;\n+\n+            // T-REC-X.690-201508 sec 8.1.3\n+\n+            byte lengthOrLengthLength = source[bytesRead];\n+            bytesRead++;\n+            const byte MultiByteMarker = 0x80;\n+\n+            // 0x00-0x7F are direct length values.\n+            // 0x80 is BER/CER indefinite length.\n+            // 0x81-0xFE says that the length takes the next 1-126 bytes.\n+            // 0xFF is forbidden.\n+            if (lengthOrLengthLength == MultiByteMarker)\n+            {\n+                // T-REC-X.690-201508 sec 10.1 (DER: Length forms)\n+                if (ruleSet == AsnEncodingRules.DER)\n+                {\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                // Null length == indefinite.\n+                return true;\n+            }\n+\n+            if (lengthOrLengthLength < MultiByteMarker)\n+            {\n+                length = lengthOrLengthLength;\n+                return true;\n+            }\n+\n+            if (lengthOrLengthLength == 0xFF)\n+            {\n+                bytesRead = 0;\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            byte lengthLength = (byte)(lengthOrLengthLength & ~MultiByteMarker);\n+\n+            // +1 for lengthOrLengthLength\n+            if (lengthLength + 1 > source.Length)\n+            {\n+                bytesRead = 0;\n+                return false;\n+            }\n+\n+            // T-REC-X.690-201508 sec 9.1 (CER: Length forms)\n+            // T-REC-X.690-201508 sec 10.1 (DER: Length forms)\n+            bool minimalRepresentation =\n+                ruleSet == AsnEncodingRules.DER || ruleSet == AsnEncodingRules.CER;\n+\n+            // The ITU-T specifications tecnically allow lengths up to ((2^128) - 1), but\n+            // since Span's length is a signed Int32 we're limited to identifying memory\n+            // that is within ((2^31) - 1) bytes of the tag start.\n+            if (minimalRepresentation && lengthLength > sizeof(int))\n+            {\n+                bytesRead = 0;\n+                return false;\n+            }\n+\n+            uint parsedLength = 0;\n+\n+            for (int i = 0; i < lengthLength; i++)\n+            {\n+                byte current = source[bytesRead];\n+                bytesRead++;\n+\n+                if (parsedLength == 0)\n+                {\n+                    if (minimalRepresentation && current == 0)\n+                    {\n+                        bytesRead = 0;\n+                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                    }\n+\n+                    if (!minimalRepresentation && current != 0)\n+                    {\n+                        // Under BER rules we could have had padding zeros, so\n+                        // once the first data bits come in check that we fit within\n+                        // sizeof(int) due to Span bounds.\n+\n+                        if (lengthLength - i > sizeof(int))\n+                        {\n+                            bytesRead = 0;\n+                            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                        }\n+                    }\n+                }\n+\n+                parsedLength <<= 8;\n+                parsedLength |= current;\n+            }\n+\n+            // This value cannot be represented as a Span length.\n+            if (parsedLength > int.MaxValue)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            if (minimalRepresentation && parsedLength < MultiByteMarker)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            length = (int)parsedLength;\n+            return true;\n+        }\n+\n+        internal (Asn1Tag, int?) ReadTagAndLength(out int bytesRead)\n+        {\n+            if (TryPeekTag(_data.Span, out Asn1Tag tag, out int tagBytesRead) &&\n+                TryReadLength(_data.Slice(tagBytesRead).Span, _ruleSet, out int? length, out int lengthBytesRead))\n+            {\n+                int allBytesRead = tagBytesRead + lengthBytesRead;\n+\n+                if (tag.IsConstructed)\n+                {\n+                    // T-REC-X.690-201508 sec 9.1 (CER: Length forms) says constructed is always indefinite.\n+                    if (_ruleSet == AsnEncodingRules.CER && length != null)\n+                    {\n+                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                    }\n+                }\n+                else if (length == null)\n+                {\n+                    // T-REC-X.690-201508 sec 8.1.3.2 says primitive encodings must use a definite form.\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                bytesRead = allBytesRead;\n+                return (tag, length);\n+            }\n+\n+            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+        }\n+\n+        private static void ValidateEndOfContents(Asn1Tag tag, int? length, int headerLength)\n+        {\n+            // T-REC-X.690-201508 sec 8.1.5 excludes the BER 8100 length form for 0.\n+            if (tag.IsConstructed || length != 0 || headerLength != EndOfContentsEncodedLength)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+        }\n+\n+        private static ReadOnlyMemory<byte> SeekEndOfContents(\n+            ReadOnlyMemory<byte> source,\n+            AsnEncodingRules ruleSet,\n+            int initialSliceOffset = 0)\n+        {\n+            ReadOnlyMemory<byte> cur = source.Slice(initialSliceOffset);\n+            int totalLen = 0;\n+\n+            while (!cur.IsEmpty)\n+            {\n+                AsnReader reader = new AsnReader(cur, ruleSet);\n+                (Asn1Tag tag, int? length) = reader.ReadTagAndLength(out int bytesRead);\n+                ReadOnlyMemory<byte> nestedContents = reader.PeekContentBytes();\n+\n+                int localLen = bytesRead + nestedContents.Length;\n+\n+                if (tag == Asn1Tag.EndOfContents)\n+                {\n+                    ValidateEndOfContents(tag, length, bytesRead);\n+\n+                    return source.Slice(0, totalLen + initialSliceOffset);\n+                }\n+\n+                // If the current value was an indefinite-length-encoded value\n+                // then we need to skip over the EOC as well.  But we didn't want to\n+                // include it as part of the content span.\n+                //\n+                // T-REC-X.690-201508 sec 8.1.1.1 / 8.1.1.3 indicate that the\n+                // End -of-Contents octets are \"after\" the contents octets, not\n+                // \"at the end\" of them.\n+                if (length == null)\n+                {\n+                    localLen += EndOfContentsEncodedLength;\n+                }\n+\n+                totalLen += localLen;\n+                cur = cur.Slice(localLen);\n+            }\n+\n+            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+        }\n+\n+        public ReadOnlyMemory<byte> PeekEncodedValue()\n+        {\n+            (Asn1Tag tag, int? length) = ReadTagAndLength(out int bytesRead);\n+\n+            if (length == null)\n+            {\n+                var tagLengthAndContents = SeekEndOfContents(_data, _ruleSet, bytesRead);\n+                return Slice(_data, 0, tagLengthAndContents.Length + EndOfContentsEncodedLength);\n+            }\n+\n+            return Slice(_data, 0, bytesRead + length.Value);\n+        }\n+\n+        public ReadOnlyMemory<byte> PeekContentBytes()\n+        {\n+            (Asn1Tag tag, int? length) = ReadTagAndLength(out int bytesRead);\n+\n+            if (length == null)\n+            {\n+                return SeekEndOfContents(_data.Slice(bytesRead), _ruleSet);\n+            }\n+\n+            return Slice(_data, bytesRead, length.Value);\n+        }\n+\n+        public void SkipValue()\n+        {\n+            GetEncodedValue();\n+        }\n+\n+        public ReadOnlyMemory<byte> GetEncodedValue()\n+        {\n+            ReadOnlyMemory<byte> encodedValue = PeekEncodedValue();\n+            _data = _data.Slice(encodedValue.Length);\n+            return encodedValue;\n+        }\n+\n+        private static bool ReadBooleanValue(\n+            ReadOnlySpan<byte> source,\n+            AsnEncodingRules ruleSet)\n+        {\n+            // T-REC-X.690-201508 sec 8.2.1\n+            if (source.Length != 1)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            byte val = source[0];\n+\n+            // T-REC-X.690-201508 sec 8.2.2\n+            if (val == 0)\n+            {\n+                return false;\n+            }\n+\n+            // T-REC-X.690-201508 sec 11.1\n+            if (val != 0xFF && (ruleSet == AsnEncodingRules.DER || ruleSet == AsnEncodingRules.CER))\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            return true;\n+        }\n+\n+        public bool ReadBoolean() => ReadBoolean(new Asn1Tag(UniversalTagNumber.Boolean));\n+\n+        public bool ReadBoolean(Asn1Tag expectedTag)\n+        {\n+            (Asn1Tag tag, int? length) = ReadTagAndLength(out int headerLength);\n+            CheckExpectedTag(tag, expectedTag, UniversalTagNumber.Boolean);\n+\n+            // T-REC-X.690-201508 sec 8.2.1\n+            if (tag.IsConstructed)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            bool value = ReadBooleanValue(\n+                Slice(_data, headerLength, length.Value).Span,\n+                _ruleSet);\n+\n+            _data = _data.Slice(headerLength + length.Value);\n+            return value;\n+        }\n+\n+        private ReadOnlyMemory<byte> GetIntegerContents(\n+            Asn1Tag expectedTag,\n+            UniversalTagNumber tagNumber,\n+            out int headerLength)\n+        {\n+            (Asn1Tag tag, int? length) = ReadTagAndLength(out headerLength);\n+            CheckExpectedTag(tag, expectedTag, tagNumber);\n+\n+            // T-REC-X.690-201508 sec 8.3.1\n+            if (tag.IsConstructed || length < 1)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            // Slice first so that an out of bounds value triggers a CryptographicException.\n+            ReadOnlyMemory<byte> contents = Slice(_data, headerLength, length.Value);\n+            ReadOnlySpan<byte> contentSpan = contents.Span;\n+\n+            // T-REC-X.690-201508 sec 8.3.2\n+            if (contents.Length > 1)\n+            {\n+                ushort bigEndianValue = (ushort)(contentSpan[0] << 8 | contentSpan[1]);\n+                const ushort RedundancyMask = 0b1111_1111_1000_0000;\n+                ushort masked = (ushort)(bigEndianValue & RedundancyMask);\n+\n+                // If the first 9 bits are all 0 or are all 1, the value is invalid.\n+                if (masked == 0 || masked == RedundancyMask)\n+                {\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+            }\n+\n+            return contents;\n+        }\n+\n+        public ReadOnlyMemory<byte> GetIntegerBytes() =>\n+            GetIntegerBytes(new Asn1Tag(UniversalTagNumber.Integer));\n+\n+        public ReadOnlyMemory<byte> GetIntegerBytes(Asn1Tag expectedTag)\n+        {\n+            ReadOnlyMemory<byte> contents =\n+                GetIntegerContents(expectedTag, UniversalTagNumber.Integer, out int headerLength);\n+\n+            _data = _data.Slice(headerLength + contents.Length);\n+            return contents;\n+        }\n+\n+        private bool TryReadSignedInteger(\n+            int sizeLimit,\n+            Asn1Tag expectedTag,\n+            UniversalTagNumber tagNumber,\n+            out long value)\n+        {\n+            Debug.Assert(sizeLimit <= sizeof(long));\n+\n+            ReadOnlyMemory<byte> contents = GetIntegerContents(expectedTag, tagNumber, out int headerLength);\n+\n+            if (contents.Length > sizeLimit)\n+            {\n+                value = 0;\n+                return false;\n+            }\n+\n+            ReadOnlySpan<byte> contentSpan = contents.Span;\n+\n+            bool isNegative = contentSpan[0] >= 0x80;\n+            long accum = isNegative ? -1 : 0;\n+\n+            for (int i = 0; i < contents.Length; i++)\n+            {\n+                accum <<= 8;\n+                accum |= contentSpan[i];\n+            }\n+\n+            _data = _data.Slice(headerLength + contents.Length);\n+            value = accum;\n+            return true;\n+        }\n+\n+        private bool TryReadUnsignedInteger(\n+            int sizeLimit,\n+            Asn1Tag expectedTag,\n+            UniversalTagNumber tagNumber,\n+            out ulong value)\n+        {\n+            Debug.Assert(sizeLimit <= sizeof(ulong));\n+\n+            ReadOnlyMemory<byte> contents = GetIntegerContents(expectedTag, tagNumber, out int headerLength);\n+            ReadOnlySpan<byte> contentSpan = contents.Span;\n+            int contentLength = contents.Length;\n+\n+            bool isNegative = contentSpan[0] >= 0x80;\n+\n+            if (isNegative)\n+            {\n+                // TODO/Review: Should this be \"false\", an Exception, or not a scenario?\n+                value = 0;\n+                return false;\n+            }\n+\n+            // Ignore any padding zeros.\n+            if (contentSpan.Length > 1 && contentSpan[0] == 0)\n+            {\n+                contentSpan = contentSpan.Slice(1);\n+            }\n+\n+            if (contentSpan.Length > sizeLimit)\n+            {\n+                value = 0;\n+                return false;\n+            }\n+\n+            ulong accum = 0;\n+\n+            for (int i = 0; i < contentSpan.Length; i++)\n+            {\n+                accum <<= 8;\n+                accum |= contentSpan[i];\n+            }\n+\n+            _data = _data.Slice(headerLength + contentLength);\n+            value = accum;\n+            return true;\n+        }\n+\n+        public bool TryReadInt32(out int value) =>\n+            TryReadInt32(new Asn1Tag(UniversalTagNumber.Integer), out value);\n+\n+        public bool TryReadInt32(Asn1Tag expectedTag, out int value)\n+        {\n+            if (TryReadSignedInteger(sizeof(int), expectedTag, UniversalTagNumber.Integer, out long longValue))\n+            {\n+                value = (int)longValue;\n+                return true;\n+            }\n+\n+            value = 0;\n+            return false;\n+        }\n+\n+        public bool TryReadUInt32(out uint value) =>\n+            TryReadUInt32(new Asn1Tag(UniversalTagNumber.Integer), out value);\n+\n+        public bool TryReadUInt32(Asn1Tag expectedTag, out uint value)\n+        {\n+            if (TryReadUnsignedInteger(sizeof(uint), expectedTag, UniversalTagNumber.Integer, out ulong ulongValue))\n+            {\n+                value = (uint)ulongValue;\n+                return true;\n+            }\n+\n+            value = 0;\n+            return false;\n+        }\n+\n+        public bool TryReadInt64(out long value) =>\n+            TryReadInt64(new Asn1Tag(UniversalTagNumber.Integer), out value);\n+        \n+        public bool TryReadInt64(Asn1Tag expectedTag, out long value)\n+        {\n+            return TryReadSignedInteger(sizeof(long), expectedTag, UniversalTagNumber.Integer, out value);\n+        }\n+\n+        public bool TryReadUInt64(out ulong value) =>\n+            TryReadUInt64(new Asn1Tag(UniversalTagNumber.Integer), out value);\n+\n+        public bool TryReadUInt64(Asn1Tag expectedTag, out ulong value)\n+        {\n+            return TryReadUnsignedInteger(sizeof(ulong), expectedTag, UniversalTagNumber.Integer, out value);\n+        }\n+\n+        public bool TryReadInt16(out short value) =>\n+            TryReadInt16(new Asn1Tag(UniversalTagNumber.Integer), out value);\n+\n+        public bool TryReadInt16(Asn1Tag expectedTag, out short value)\n+        {\n+            if (TryReadSignedInteger(sizeof(short), expectedTag, UniversalTagNumber.Integer, out long longValue))\n+            {\n+                value = (short)longValue;\n+                return true;\n+            }\n+\n+            value = 0;\n+            return false;\n+        }\n+\n+        public bool TryReadUInt16(out ushort value) =>\n+            TryReadUInt16(new Asn1Tag(UniversalTagNumber.Integer), out value);\n+\n+        public bool TryReadUInt16(Asn1Tag expectedTag, out ushort value)\n+        {\n+            if (TryReadUnsignedInteger(sizeof(ushort), expectedTag, UniversalTagNumber.Integer, out ulong ulongValue))\n+            {\n+                value = (ushort)ulongValue;\n+                return true;\n+            }\n+\n+            value = 0;\n+            return false;\n+        }\n+\n+        public bool TryReadInt8(out sbyte value) =>\n+            TryReadInt8(new Asn1Tag(UniversalTagNumber.Integer), out value);\n+\n+        public bool TryReadInt8(Asn1Tag expectedTag, out sbyte value)\n+        {\n+            if (TryReadSignedInteger(sizeof(sbyte), expectedTag, UniversalTagNumber.Integer, out long longValue))\n+            {\n+                value = (sbyte)longValue;\n+                return true;\n+            }\n+\n+            value = 0;\n+            return false;\n+        }\n+\n+        public bool TryReadUInt8(out byte value) =>\n+            TryReadUInt8(new Asn1Tag(UniversalTagNumber.Integer), out value);\n+\n+        public bool TryReadUInt8(Asn1Tag expectedTag, out byte value)\n+        {\n+            if (TryReadUnsignedInteger(sizeof(byte), expectedTag, UniversalTagNumber.Integer, out ulong ulongValue))\n+            {\n+                value = (byte)ulongValue;\n+                return true;\n+            }\n+\n+            value = 0;\n+            return false;\n+        }\n+\n+        private static bool TryCopyPrimitiveBitStringValue(\n+            ReadOnlyMemory<byte> source,\n+            Span<byte> destination,\n+            bool write,\n+            bool requireBerMaskMatch,\n+            AsnEncodingRules ruleSet,\n+            out int unusedBitCount,\n+            out int bytesWritten)\n+        {\n+            // T-REC-X.690-201508 sec 9.2\n+            if (ruleSet == AsnEncodingRules.CER && source.Length > MaxCERSegmentSize)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            if (write && destination.Length < source.Length - 1)\n+            {\n+                unusedBitCount = bytesWritten = 0;\n+                return false;\n+            }\n+\n+            // T-REC-X.690-201508 sec 8.6.2.3\n+            if (source.Length < 1)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            ReadOnlySpan<byte> sourceSpan = source.Span;\n+            unusedBitCount = sourceSpan[0];\n+\n+            // T-REC-X.690-201508 sec 8.6.2.2\n+            if (unusedBitCount > 7)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            if (source.Length == 1)\n+            {\n+                // T-REC-X.690-201508 sec 8.6.2.4\n+                if (unusedBitCount > 0)\n+                {\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                unusedBitCount = 0;\n+                bytesWritten = 0;\n+                return true;\n+            }\n+\n+            // If 3 bits are \"unused\" then build a mask for the top 5 bits.\n+            // 0b1111_1111 >> (8 - 3)\n+            // 0b1111_1111 >> 5\n+            // 0b0000_0111\n+            // (then invert that)\n+            // 0b1111_1000\n+            byte mask = (byte)~(0xFF >> (8 - unusedBitCount));\n+            byte lastByte = sourceSpan[sourceSpan.Length - 1];\n+            byte maskedByte = (byte)(lastByte & mask);\n+\n+            if (maskedByte == lastByte)\n+            {\n+                if (write)\n+                {\n+                    sourceSpan.Slice(1).CopyTo(destination);\n+                }\n+\n+                bytesWritten = source.Length - 1;\n+                return true;\n+            }\n+\n+            // T-REC-X.690-201508 sec 11.2.1\n+            if (ruleSet == AsnEncodingRules.DER || ruleSet == AsnEncodingRules.CER)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            if (requireBerMaskMatch)\n+            {\n+                bytesWritten = 0;\n+                unusedBitCount = 0;\n+                return false;\n+            }\n+\n+            if (write)\n+            {\n+                sourceSpan.Slice(1, sourceSpan.Length - 2).CopyTo(destination);\n+                destination[source.Length - 2] = maskedByte;\n+            }\n+\n+            bytesWritten = source.Length - 1;\n+            return true;\n+        }\n+\n+        private static int CopyConstructedBitString(\n+            ReadOnlyMemory<byte> source,\n+            ref Span<byte> destination,\n+            bool write,\n+            AsnEncodingRules ruleSet,\n+            bool isIndefinite,\n+            ref int lastUnusedBitCount,\n+            ref int lastSegmentLength,\n+            out int bytesRead)\n+        {\n+            if (source.IsEmpty)\n+            {\n+                if (isIndefinite)\n+                {\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                bytesRead = 0;\n+                return 0;\n+            }\n+\n+            int totalRead = 0;\n+            int totalContent = 0;\n+            ReadOnlyMemory<byte> cur = source;\n+\n+            while (!cur.IsEmpty)\n+            {\n+                AsnReader reader = new AsnReader(cur, ruleSet);\n+                (Asn1Tag tag, int? length) = reader.ReadTagAndLength(out int headerLength);\n+\n+                if (tag.TagClass != TagClass.Universal)\n+                {\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                totalRead += headerLength;\n+\n+                if (isIndefinite && tag.TagValue == (int)UniversalTagNumber.EndOfContents)\n+                {\n+                    ValidateEndOfContents(tag, length, headerLength);\n+\n+                    bytesRead = totalRead;\n+                    return totalContent;\n+                }\n+\n+                if (tag.TagValue != (int)UniversalTagNumber.BitString)\n+                {\n+                    // T-REC-X.690-201508 sec 8.6.4.1 (in particular, Note 2)\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                if (ruleSet == AsnEncodingRules.CER)\n+                {\n+                    if (tag.IsConstructed || lastSegmentLength != MaxCERSegmentSize)\n+                    {\n+                        // T-REC-X.690-201508 sec 9.2\n+                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                    }\n+                }\n+\n+                cur = cur.Slice(headerLength);\n+\n+                if (length == null)\n+                {\n+                    totalContent += CopyConstructedBitString(\n+                        cur,\n+                        ref destination,\n+                        write,\n+                        ruleSet,\n+                        true,\n+                        ref lastUnusedBitCount,\n+                        ref lastSegmentLength,\n+                        out int nestedBytesRead);\n+\n+                    totalRead += nestedBytesRead;\n+                    cur = cur.Slice(nestedBytesRead);\n+                }\n+                else if (tag.IsConstructed)\n+                {\n+                    totalContent += CopyConstructedBitString(\n+                        Slice(cur, 0, length.Value),\n+                        ref destination,\n+                        write,\n+                        ruleSet,\n+                        false,\n+                        ref lastUnusedBitCount,\n+                        ref lastSegmentLength,\n+                        out int nestedContentRead);\n+\n+                    totalRead += nestedContentRead;\n+                    cur = cur.Slice(nestedContentRead);\n+                }\n+                else\n+                {\n+                    if (lastUnusedBitCount != 0)\n+                    {\n+                        // T-REC-X.690-201508 sec 8.6.4 (only the last segment can have unused bits)\n+                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                    }\n+\n+                    int lengthValue = length.Value;\n+\n+                    TryCopyPrimitiveBitStringValue(\n+                        Slice(cur, 0, lengthValue),\n+                        destination,\n+                        write,\n+                        false,\n+                        ruleSet,\n+                        out lastUnusedBitCount,\n+                        out int pretendWritten);\n+\n+                    totalRead += lengthValue;\n+                    totalContent += pretendWritten;\n+                    lastSegmentLength = lengthValue;\n+                    cur = cur.Slice(lengthValue);\n+\n+                    if (write)\n+                    {\n+                        destination = destination.Slice(pretendWritten);\n+                    }\n+                }\n+            }\n+\n+            if (isIndefinite)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            bytesRead = totalRead;\n+            return totalContent;\n+        }\n+\n+        private static bool TryCopyConstructedBitStringValue(\n+            ReadOnlyMemory<byte> source,\n+            Span<byte> dest,\n+            AsnEncodingRules ruleSet,\n+            bool isIndefinite,\n+            out int unusedBitCount,\n+            out int bytesRead,\n+            out int bytesWritten)\n+        {\n+            int lastUnusedBitCount = 0;\n+            int lastSegmentSize = MaxCERSegmentSize;\n+\n+            Span<byte> tmpDest = dest;\n+\n+            int contentLength = CopyConstructedBitString(\n+                source,\n+                ref tmpDest,\n+                false,\n+                ruleSet,\n+                isIndefinite,\n+                ref lastUnusedBitCount,\n+                ref lastSegmentSize,\n+                out int encodedLength);\n+\n+            // Since the unused bits byte from the segments don't count, only one segment\n+            // returns 999 (or less), the second segment bumps the count to 1000, and is legal.\n+            //\n+            // T-REC-X.690-201508 sec 9.2\n+            if (ruleSet == AsnEncodingRules.CER && contentLength < MaxCERSegmentSize)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            if (dest.Length < contentLength)\n+            {\n+                unusedBitCount = 0;\n+                bytesRead = 0;\n+                bytesWritten = 0;\n+                return false;\n+            }\n+\n+            tmpDest = dest;\n+            unusedBitCount = lastUnusedBitCount;\n+            lastSegmentSize = MaxCERSegmentSize;\n+            lastUnusedBitCount = 0;\n+\n+            bytesWritten = CopyConstructedBitString(\n+                source,\n+                ref tmpDest,\n+                true,\n+                ruleSet,\n+                isIndefinite,\n+                ref lastUnusedBitCount,\n+                ref lastSegmentSize,\n+                out bytesRead);\n+\n+            Debug.Assert(unusedBitCount == lastUnusedBitCount);\n+            Debug.Assert(bytesWritten == contentLength);\n+            Debug.Assert(bytesRead == encodedLength);\n+            return true;\n+        }\n+\n+        private bool TryGetBitStringBytes(\n+            Asn1Tag expectedTag,\n+            out int unusedBitCount,\n+            out ReadOnlyMemory<byte> contents,\n+            out int headerLength)\n+        {\n+            (Asn1Tag tag, int? length) = ReadTagAndLength(out headerLength);\n+            CheckExpectedTag(tag, expectedTag, UniversalTagNumber.BitString);\n+\n+            if (tag.IsConstructed)\n+            {\n+                if (_ruleSet == AsnEncodingRules.DER)\n+                {\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                contents = default(ReadOnlyMemory<byte>);\n+                unusedBitCount = 0;\n+                return false;\n+            }\n+\n+            Debug.Assert(length.HasValue);\n+            ReadOnlyMemory<byte> encodedValue = Slice(_data, headerLength, length.Value);\n+\n+            if (TryCopyPrimitiveBitStringValue(\n+                encodedValue,\n+                Span<byte>.Empty,\n+                false,\n+                true,\n+                _ruleSet,\n+                out unusedBitCount,\n+                out int bytesWritten))\n+            {\n+                contents = encodedValue.Slice(1);\n+                return true;\n+            }\n+\n+            contents = default(ReadOnlyMemory<byte>);\n+            return false;\n+        }\n+\n+        public bool TryGetBitStringBytes(out int unusedBitCount, out ReadOnlyMemory<byte> contents)\n+            => TryGetBitStringBytes(new Asn1Tag(UniversalTagNumber.BitString), out unusedBitCount, out contents);\n+\n+        /// <summary>\n+        /// Gets the source data for a BitString under a primitive encoding.\n+        /// </summary>\n+        /// <param name=\"expectedTag\">The expected tag to read</param>\n+        /// <param name=\"unusedBitCount\">The encoded value for the number of unused bits.</param>\n+        /// <param name=\"contents\">The content bytes for the BitString payload.</param>\n+        /// <returns>\n+        ///   <c>true</c> if the bit string uses a primitive encoding and the \"unused\" bits have value 0,\n+        ///   <c>false</c> otherwise.\n+        /// </returns>\n+        /// <exception cref=\"CryptographicException\">\n+        ///  <ul>\n+        ///   <li>No data remains</li>\n+        ///   <li>The tag read does not match the expected tag</li>\n+        ///   <li>The length is invalid under the chosen encoding rules</li>\n+        ///   <li>The unusedBitCount value is out of bounds</li>\n+        ///   <li>A CER or DER encoding was chosen and an \"unused\" bit was set to 1</li>\n+        ///   <li>A CER encoding was chosen and the primitive content length exceeds the maximum allowed</li>\n+        /// </ul>\n+        /// </exception>\n+        public bool TryGetBitStringBytes(\n+            Asn1Tag expectedTag,\n+            out int unusedBitCount,\n+            out ReadOnlyMemory<byte> contents)\n+        {\n+            bool didGet = TryGetBitStringBytes(expectedTag, out unusedBitCount, out contents, out int headerLength);\n+\n+            if (didGet)\n+            {\n+                // Skip the tag+length (header) and the unused bit count byte (1) and the contents.\n+                _data = _data.Slice(headerLength + contents.Length + 1);\n+            }\n+\n+            return didGet;\n+        }\n+\n+        public bool TryCopyBitStringBytes(\n+            Span<byte> destination,\n+            out int unusedBitCount,\n+            out int bytesWritten)\n+        {\n+            return TryCopyBitStringBytes(\n+                new Asn1Tag(UniversalTagNumber.BitString),\n+                destination,\n+                out unusedBitCount,\n+                out bytesWritten);\n+        }\n+\n+        public bool TryCopyBitStringBytes(\n+            Asn1Tag expectedTag,\n+            Span<byte> destination,\n+            out int unusedBitCount,\n+            out int bytesWritten)\n+        {\n+            if (TryGetBitStringBytes(\n+                expectedTag,\n+                out unusedBitCount,\n+                out ReadOnlyMemory<byte> contents,\n+                out int headerLength))\n+            {\n+                if (contents.Length > destination.Length)\n+                {\n+                    bytesWritten = 0;\n+                    unusedBitCount = 0;\n+                    return false;\n+                }\n+\n+                contents.Span.CopyTo(destination);\n+                bytesWritten = contents.Length;\n+                // contents doesn't include the unusedBitCount value, so add one byte for that.\n+                _data = _data.Slice(headerLength + contents.Length + 1);\n+                return true;\n+            }\n+\n+            // Expected vs actual tag was already checked in TryGetBitStringBytes.\n+            // Either constructed, or a BER payload with \"unused\" bits not set to 0.\n+            (Asn1Tag tag, int? length) = ReadTagAndLength(out headerLength);\n+\n+            if (!tag.IsConstructed)\n+            {\n+                Debug.Assert(_ruleSet == AsnEncodingRules.BER);\n+\n+                return TryCopyPrimitiveBitStringValue(\n+                    Slice(_data, headerLength, length),\n+                    destination,\n+                    true,\n+                    false,\n+                    _ruleSet,\n+                    out unusedBitCount,\n+                    out bytesWritten);\n+            }\n+\n+            bool read = TryCopyConstructedBitStringValue(\n+                Slice(_data, headerLength, length),\n+                destination,\n+                _ruleSet,\n+                length == null,\n+                out unusedBitCount,\n+                out int bytesRead,\n+                out bytesWritten);\n+\n+            if (read)\n+            {\n+                _data = _data.Slice(headerLength + bytesRead);\n+            }\n+\n+            return read;\n+        }\n+\n+        public TFlagsEnum GetNamedBitListValue<TFlagsEnum>(NamedBitListMode mode) where TFlagsEnum : struct =>\n+            GetNamedBitListValue<TFlagsEnum>(new Asn1Tag(UniversalTagNumber.BitString), mode);\n+\n+        public TFlagsEnum GetNamedBitListValue<TFlagsEnum>(Asn1Tag expectedTag, NamedBitListMode mode) where TFlagsEnum : struct\n+        {\n+            Type tFlagsEnum = typeof(TFlagsEnum);\n+\n+            return (TFlagsEnum)Enum.ToObject(tFlagsEnum, GetNamedBitListValue(expectedTag, tFlagsEnum, mode));\n+        }\n+\n+        public Enum GetNamedBitListValue(Type tFlagsEnum, NamedBitListMode mode) =>\n+            GetNamedBitListValue(new Asn1Tag(UniversalTagNumber.BitString), tFlagsEnum, mode);\n+\n+        public Enum GetNamedBitListValue(Asn1Tag expectedTag, Type tFlagsEnum, NamedBitListMode mode)\n+        {\n+            // This will throw an ArgumentException if TEnum isn't an enum type,\n+            // so we don't need to validate it.\n+            Type backingType = tFlagsEnum.GetEnumUnderlyingType();\n+\n+            if (!tFlagsEnum.IsDefined(typeof(FlagsAttribute), false))\n+            {\n+                throw new ArgumentException(\n+                    SR.Cryptography_Asn_NamedBitListRequiresFlagsEnum,\n+                    nameof(tFlagsEnum));\n+            }\n+\n+            if (mode != NamedBitListMode.NamedZeroIsOne &&\n+                mode != NamedBitListMode.NamedZeroIs128LittleEndian &&\n+                mode != NamedBitListMode.NamedZeroIs128BigEndian)\n+            {\n+                throw new ArgumentOutOfRangeException(nameof(mode));\n+            }\n+\n+            int sizeLimit = Marshal.SizeOf(backingType);\n+            Span<byte> stackSpan = stackalloc byte[1 + sizeLimit];\n+            ReadOnlyMemory<byte> saveData = _data;\n+\n+            if (!TryCopyBitStringBytes(expectedTag, stackSpan, out int unusedBitCount, out int bytesWritten))\n+            {\n+                throw new CryptographicException(\n+                    SR.Format(SR.Cryptography_Asn_NamedBitListValueTooBig, tFlagsEnum.Name));\n+            }\n+\n+            if (bytesWritten == 0)\n+            {\n+                // The mode isn't relevant, zero is always zero.\n+                return (Enum)Enum.ToObject(tFlagsEnum, 0);\n+            }\n+\n+            ReadOnlySpan<byte> valueSpan = stackSpan.Slice(0, bytesWritten);\n+\n+            // Now that the 0-bounds check is out of the way:\n+            // \n+            // T-REC-X.690-201508 sec 11.2.2\n+            if (_ruleSet == AsnEncodingRules.DER ||\n+                _ruleSet == AsnEncodingRules.CER)\n+            {\n+                byte lastByte = valueSpan[bytesWritten - 1];\n+\n+                // No unused bits tests 0x01, 1 is 0x02, 2 is 0x04, etc.\n+                // We already know that TryCopyBitStringBytes checked that the\n+                // declared unused bits were 0, this checks that the last \"used\" bit\n+                // isn't also zero.\n+                byte testBit = (byte)(1 << unusedBitCount);\n+\n+                if ((lastByte & testBit) == 0)\n+                {\n+                    _data = saveData;\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+            }\n+\n+            // Consider a NamedBitList defined as\n+            //\n+            //   SomeList ::= BIT STRING {\n+            //     a(0), b(1), c(2), d(3), e(4), f(5), g(6), h(7), i(8), j(9), k(10)\n+            //   }\n+            //\n+            // The BIT STRING encoding of (a | j) is\n+            //   unusedBitCount = 6,\n+            //   contents: 0x80 0x40  (0b10000000_01000000)\n+            //\n+            // A reasonable C# exposure of this structure is\n+            //\n+            // [Flags]\n+            // enum SomeList : ushort\n+            // {\n+            //     A = 1,\n+            //     B = 1 << 1,\n+            //     C = 1 << 2,\n+            //     ...\n+            // }\n+            //\n+            // In NamedZeroIsOne we will make that enum work.\n+            //\n+            // In NamedZeroIs128LittleEndian the enum would be\n+            //\n+            // [Flags]\n+            // enum SomeList : ushort\n+            // {\n+            //     A = 0x80,\n+            //     B = 0x40,\n+            //     C = 0x20,\n+            //     ...\n+            //     H = 0x01,\n+            //     I = 0x8000,\n+            //     ...\n+            // }\n+            //\n+            // In NamedZeroIs128BigEndian the enum would be\n+            //\n+            // [Flags]\n+            // enum SomeList : ushort\n+            // {\n+            //     A = 0x8000,\n+            //     B = 0x4000,\n+            //     C = 0x2000,\n+            //     ...\n+            //     H = 0x0100,\n+            //     I = 0x0080,\n+            //     ...\n+            // }\n+            //\n+            // NamedZeroIs128BigEndian is the most brittle, because if additional\n+            // values increase the number of bytes required in the encoding everything\n+            // needs to be renumbered.\n+            //\n+            // NamedZeroIs128LittleEndian requires a bit of mental gymnastics to understand,\n+            // but it is (up to 64 bits) a sensibly extensible model.\n+            //\n+            // NamedZeroIsOne matches the way that enumerations grow in C#, but it happens\n+            // to be exactly backward from the storage mechanism.\n+            //\n+            // (There should be a fourth ordering, where bits increase in value left to right,\n+            // but bytes decrease in value.  But it's not obvious why anyone would want it, or\n+            // what to call it)\n+\n+            long value;\n+\n+            switch (mode)\n+            {\n+                case NamedBitListMode.NamedZeroIsOne:\n+                    value = InterpretNamedBitListReversed(valueSpan);\n+                    break;\n+                case NamedBitListMode.NamedZeroIs128LittleEndian:\n+                    value = InterpretNamedBitListBytesLE(valueSpan);\n+                    break;\n+                case NamedBitListMode.NamedZeroIs128BigEndian:\n+                    value = InterpretNamedBitListBytesBE(valueSpan, sizeLimit);\n+                    break;\n+                default:\n+                    Debug.Fail($\"Unhandled mode ({mode}) did not already trigger an ArgumentOutOfRangeException\");\n+                    _data = saveData;\n+                    throw new ArgumentOutOfRangeException(nameof(mode));\n+            }\n+\n+            return (Enum)Enum.ToObject(tFlagsEnum, value);\n+        }\n+\n+        private static long InterpretNamedBitListReversed(ReadOnlySpan<byte> valueSpan)\n+        {\n+            Debug.Assert(valueSpan.Length <= sizeof(long));\n+\n+            long accum = 0;\n+            long currentBitValue = 1;\n+\n+            for (int byteIdx = 0; byteIdx < valueSpan.Length; byteIdx++)\n+            {\n+                byte byteVal = valueSpan[byteIdx];\n+\n+                for (int bitIndex = 7; bitIndex >= 0; bitIndex--)\n+                {\n+                    int test = 1 << bitIndex;\n+\n+                    if ((byteVal & test) != 0)\n+                    {\n+                        accum |= currentBitValue;\n+                    }\n+\n+                    currentBitValue <<= 1;\n+                }\n+            }\n+\n+            return accum;\n+        }\n+\n+        private static long InterpretNamedBitListBytesLE(ReadOnlySpan<byte> valueSpan)\n+        {\n+            Debug.Assert(valueSpan.Length <= sizeof(long));\n+\n+            long accum = 0;\n+\n+            for (int byteIdx = 0; byteIdx < valueSpan.Length; byteIdx++)\n+            {\n+                long positionValue = valueSpan[byteIdx];\n+\n+                positionValue <<= (8 * byteIdx);\n+                accum |= positionValue;\n+            }\n+\n+            return accum;\n+        }\n+\n+        private static long InterpretNamedBitListBytesBE(ReadOnlySpan<byte> valueSpan, int sizeLimit)\n+        {\n+            Debug.Assert(valueSpan.Length <= sizeof(long));\n+\n+            long accum = 0;\n+\n+            for (int byteIdx = 0; byteIdx < valueSpan.Length; byteIdx++)\n+            {\n+                long positionValue = valueSpan[byteIdx];\n+\n+                accum <<= 8;\n+                accum |= positionValue;\n+            }\n+\n+            accum <<= 8 * (sizeLimit - valueSpan.Length);\n+\n+            return accum;\n+        }\n+\n+        public ReadOnlyMemory<byte> GetEnumeratedBytes() =>\n+            GetEnumeratedBytes(new Asn1Tag(UniversalTagNumber.Enumerated));\n+\n+        public ReadOnlyMemory<byte> GetEnumeratedBytes(Asn1Tag expectedTag)\n+        {\n+            // T-REC-X.690-201508 sec 8.4 says the contents are the same as for integers.\n+            ReadOnlyMemory<byte> contents =\n+                GetIntegerContents(expectedTag, UniversalTagNumber.Enumerated, out int headerLength);\n+\n+            _data = _data.Slice(headerLength + contents.Length);\n+            return contents;\n+        }\n+\n+        public TEnum GetEnumeratedValue<TEnum>() where TEnum : struct\n+        {\n+            Type tEnum = typeof(TEnum);\n+\n+            return (TEnum)Enum.ToObject(tEnum, GetEnumeratedValue(tEnum));\n+        }\n+\n+        public TEnum GetEnumeratedValue<TEnum>(Asn1Tag expectedTag) where TEnum : struct\n+        {\n+            Type tEnum = typeof(TEnum);\n+\n+            return (TEnum)Enum.ToObject(tEnum, GetEnumeratedValue(expectedTag, tEnum));\n+        }\n+\n+        public Enum GetEnumeratedValue(Type tEnum) =>\n+            GetEnumeratedValue(new Asn1Tag(UniversalTagNumber.Enumerated), tEnum);\n+\n+        public Enum GetEnumeratedValue(Asn1Tag expectedTag, Type tEnum)\n+        {\n+            const UniversalTagNumber tagNumber = UniversalTagNumber.Enumerated;\n+            \n+            // This will throw an ArgumentException if TEnum isn't an enum type,\n+            // so we don't need to validate it.\n+            Type backingType = tEnum.GetEnumUnderlyingType();\n+\n+            if (tEnum.IsDefined(typeof(FlagsAttribute), false))\n+            {\n+                throw new ArgumentException(\n+                    SR.Cryptography_Asn_EnumeratedValueRequiresNonFlagsEnum,\n+                    nameof(tEnum));\n+            }\n+\n+            // T-REC-X.690-201508 sec 8.4 says the contents are the same as for integers.\n+            int sizeLimit = Marshal.SizeOf(backingType);\n+\n+            if (backingType == typeof(int) ||\n+                backingType == typeof(long) ||\n+                backingType == typeof(short) ||\n+                backingType == typeof(sbyte))\n+            {\n+                if (!TryReadSignedInteger(sizeLimit, expectedTag, tagNumber, out long value))\n+                {\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                return (Enum)Enum.ToObject(tEnum, value);\n+            }\n+\n+            if (backingType == typeof(uint) ||\n+                backingType == typeof(ulong) ||\n+                backingType == typeof(ushort) ||\n+                backingType == typeof(byte))\n+            {\n+                if (!TryReadUnsignedInteger(sizeLimit, expectedTag, tagNumber, out ulong value))\n+                {\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                return (Enum)Enum.ToObject(tEnum, value);\n+            }\n+\n+            Debug.Fail($\"No handler for type {backingType.Name}\");\n+            throw new CryptographicException();\n+        }\n+\n+        private bool TryGetOctetStringBytes(\n+            Asn1Tag expectedTag,\n+            out ReadOnlyMemory<byte> contents,\n+            out int headerLength,\n+            UniversalTagNumber universalTagNumber = UniversalTagNumber.OctetString)\n+        {\n+            (Asn1Tag tag, int? length) = ReadTagAndLength(out headerLength);\n+            CheckExpectedTag(tag, expectedTag, universalTagNumber);\n+\n+            if (tag.IsConstructed)\n+            {\n+                if (_ruleSet == AsnEncodingRules.DER)\n+                {\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                contents = default(ReadOnlyMemory<byte>);\n+                return false;\n+            }\n+\n+            Debug.Assert(length.HasValue);\n+            ReadOnlyMemory<byte> encodedValue = Slice(_data, headerLength, length.Value);\n+\n+            if (_ruleSet == AsnEncodingRules.CER && encodedValue.Length > MaxCERSegmentSize)\n+            {\n+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+            }\n+\n+            contents = encodedValue;\n+            return true;\n+        }\n+\n+        private bool TryGetOctetStringBytes(\n+            Asn1Tag expectedTag,\n+            UniversalTagNumber universalTagNumber,\n+            out ReadOnlyMemory<byte> contents)\n+        {\n+            if (TryGetOctetStringBytes(expectedTag, out contents, out int headerLength, universalTagNumber))\n+            {\n+                _data = _data.Slice(headerLength + contents.Length);\n+                return true;\n+            }\n+\n+            return false;\n+        }\n+\n+        public bool TryGetOctetStringBytes(out ReadOnlyMemory<byte> contents) =>\n+            TryGetOctetStringBytes(new Asn1Tag(UniversalTagNumber.OctetString), out contents);\n+\n+        /// <summary>\n+        /// Gets the source data for an OctetString under a primitive encoding.\n+        /// </summary>\n+        /// <param name=\"expectedTag\">The expected tag value</param>\n+        /// <param name=\"contents\">The content bytes for the OctetString payload.</param>\n+        /// <returns>\n+        ///   <c>true</c> if the octet string uses a primitive encoding, <c>false</c> otherwise.\n+        /// </returns>\n+        /// <exception cref=\"CryptographicException\">\n+        ///  <ul>\n+        ///   <li>No data remains</li>\n+        ///   <li>The tag read did not match the expected tag</li>\n+        ///   <li>The length is invalid under the chosen encoding rules</li>\n+        ///   <li>A CER encoding was chosen and the primitive content length exceeds the maximum allowed</li>\n+        /// </ul>\n+        /// </exception>\n+        public bool TryGetOctetStringBytes(Asn1Tag expectedTag, out ReadOnlyMemory<byte> contents)\n+        {\n+            return TryGetOctetStringBytes(expectedTag, UniversalTagNumber.OctetString, out contents);\n+        }\n+\n+        private static int CopyConstructedOctetString(\n+            ReadOnlyMemory<byte> source,\n+            ref Span<byte> destination,\n+            bool write,\n+            AsnEncodingRules ruleSet,\n+            bool isIndefinite,\n+            ref int lastSegmentLength,\n+            out int bytesRead)\n+        {\n+            if (source.IsEmpty)\n+            {\n+                if (isIndefinite)\n+                {\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                bytesRead = 0;\n+                return 0;\n+            }\n+\n+            int totalRead = 0;\n+            int totalContent = 0;\n+            ReadOnlyMemory<byte> cur = source;\n+\n+            while (!cur.IsEmpty)\n+            {\n+                AsnReader reader = new AsnReader(cur, ruleSet);\n+                (Asn1Tag tag, int? length) = reader.ReadTagAndLength(out int headerLength);\n+                \n+                if (tag.TagClass != TagClass.Universal)\n+                {\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                totalRead += headerLength;\n+\n+                if (isIndefinite && tag.TagValue == (int)UniversalTagNumber.EndOfContents)\n+                {\n+                    ValidateEndOfContents(tag, length, headerLength);\n+\n+                    bytesRead = totalRead;\n+                    return totalContent;\n+                }\n+\n+                if (tag.TagValue != (int)UniversalTagNumber.OctetString)\n+                {\n+                    // T-REC-X.690-201508 sec 8.7.3.2 (in particular, Note 2)\n+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                }\n+\n+                if (ruleSet == AsnEncodingRules.CER)\n+                {\n+                    if (tag.IsConstructed || lastSegmentLength != MaxCERSegmentSize)\n+                    {\n+                        // T-REC-X.690-201508 sec 9.2\n+                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                    }\n+                }\n+\n+                cur = cur.Slice(headerLength);\n+\n+                if (length == null)\n+                {\n+                    totalContent += CopyConstructedOctetString(\n+                        cur,\n+                        ref destination,\n+                        write,\n+                        ruleSet,\n+                        true,\n+                        ref lastSegmentLength,\n+                        out int nestedBytesRead);\n+\n+                    totalRead += nestedBytesRead;\n+                    cur = cur.Slice(nestedBytesRead);\n+                }\n+                else if (tag.IsConstructed)\n+                {\n+                    totalContent += CopyConstructedOctetString(\n+                        Slice(cur, 0, length.Value),\n+                        ref destination,\n+                        write,\n+                        ruleSet,\n+                        false,\n+                        ref lastSegmentLength,\n+                        out int nestedContentRead);\n+\n+                    totalRead += nestedContentRead;\n+                    cur = cur.Slice(nestedContentRead);\n+                }\n+                else\n+                {\n+                    int lengthValue = length.Value;\n+\n+                    // T-REC-X.690-201508 sec 9.2\n+                    if (ruleSet == AsnEncodingRules.CER && lengthValue > MaxCERSegmentSize)\n+                    {\n+                        throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);\n+                    }\n+\n+                    totalRead += lengthValue;\n+                    totalContent += lengthValue;\n+                    lastSegmentLength = lengthValue;\n+\n+                    ReadOnlyMemory<byte> segment = Slice(cur, 0, lengthValue);\n+             ","path":"src/Common/src/System/Security/Cryptography/Asn1V2.cs","position":null,"original_position":4881,"commit_id":"951562711fb306b27fe5f34bd4e63d278f906256","original_commit_id":"951562711fb306b27fe5f34bd4e63d278f906256","user":{"login":"GrabYourPitchforks","id":1746272,"avatar_url":"https://avatars0.githubusercontent.com/u/1746272?v=4","gravatar_id":"","url":"https://api.github.com/users/GrabYourPitchforks","html_url":"https://github.com/GrabYourPitchforks","followers_url":"https://api.github.com/users/GrabYourPitchforks/followers","following_url":"https://api.github.com/users/GrabYourPitchforks/following{/other_user}","gists_url":"https://api.github.com/users/GrabYourPitchforks/gists{/gist_id}","starred_url":"https://api.github.com/users/GrabYourPitchforks/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/GrabYourPitchforks/subscriptions","organizations_url":"https://api.github.com/users/GrabYourPitchforks/orgs","repos_url":"https://api.github.com/users/GrabYourPitchforks/repos","events_url":"https://api.github.com/users/GrabYourPitchforks/events{/privacy}","received_events_url":"https://api.github.com/users/GrabYourPitchforks/received_events","type":"User","site_admin":false},"body":"Even though this is a Try method, it throws an exception if the internal object state is invalid. We should document this behavior since callers might not expect it.","created_at":"2017-11-22T03:46:59Z","updated_at":"2017-11-22T03:46:59Z","html_url":"https://github.com/dotnet/corefx/pull/25296#discussion_r152463461","pull_request_url":"https://api.github.com/repos/dotnet/corefx/pulls/25296","author_association":"MEMBER","_links":{"self":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/comments/152463461"},"html":{"href":"https://github.com/dotnet/corefx/pull/25296#discussion_r152463461"},"pull_request":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/25296"}}},"pull_request":{"url":"https://api.github.com/repos/dotnet/corefx/pulls/25296","id":153108710,"html_url":"https://github.com/dotnet/corefx/pull/25296","diff_url":"https://github.com/dotnet/corefx/pull/25296.diff","patch_url":"https://github.com/dotnet/corefx/pull/25296.patch","issue_url":"https://api.github.com/repos/dotnet/corefx/issues/25296","number":25296,"state":"open","locked":false,"title":"Create a Memory/Span-based ASN.1 reader and writer","user":{"login":"bartonjs","id":10642668,"avatar_url":"https://avatars3.githubusercontent.com/u/10642668?v=4","gravatar_id":"","url":"https://api.github.com/users/bartonjs","html_url":"https://github.com/bartonjs","followers_url":"https://api.github.com/users/bartonjs/followers","following_url":"https://api.github.com/users/bartonjs/following{/other_user}","gists_url":"https://api.github.com/users/bartonjs/gists{/gist_id}","starred_url":"https://api.github.com/users/bartonjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bartonjs/subscriptions","organizations_url":"https://api.github.com/users/bartonjs/orgs","repos_url":"https://api.github.com/users/bartonjs/repos","events_url":"https://api.github.com/users/bartonjs/events{/privacy}","received_events_url":"https://api.github.com/users/bartonjs/received_events","type":"User","site_admin":false},"body":"The AsnReader type can read any BER-encoded value for the types that it supports (for tag values up to int.MaxValue).  It also understands the CER and DER restrictions, and when reading in those modes it will enforce the restrictions that those encoding rulesets dictate.\r\n\r\nThe AsnWriter type mostly writes in DER (except where CER demands a different encoding). The only significant \"BER-relaxation\" it takes is that closing a SET OF value will not sort the contents.\r\n\r\nUnlike its predecessor, the DerEncoder class, AsnWriter never involves `byte[][]`.\r\n\r\nThe reader and writer (and helper classes) are all in one file because they're expected to be consumed as shared source until we're fully happy with things, then it can become public API and split into multiple files accordingly.\r\n\r\nReference materials:\r\n* [ITU-T-REC-X.680-201508](https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.680-201508-I!!PDF-E&type=items) (ASN.1 language, and some semantics behind the values)\r\n* [ITU-T-REC-X.690-201508](https://www.itu.int/rec/dologin_pub.asp?lang=e&id=T-REC-X.690-201508-I!!PDF-E&type=items) (the BER encoding family (BER, CER, DER)).","created_at":"2017-11-16T17:52:38Z","updated_at":"2017-11-22T03:46:59Z","closed_at":null,"merged_at":null,"merge_commit_sha":"9d993b6baf77885490b113dd2746f038718a02fd","assignee":{"login":"bartonjs","id":10642668,"avatar_url":"https://avatars3.githubusercontent.com/u/10642668?v=4","gravatar_id":"","url":"https://api.github.com/users/bartonjs","html_url":"https://github.com/bartonjs","followers_url":"https://api.github.com/users/bartonjs/followers","following_url":"https://api.github.com/users/bartonjs/following{/other_user}","gists_url":"https://api.github.com/users/bartonjs/gists{/gist_id}","starred_url":"https://api.github.com/users/bartonjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bartonjs/subscriptions","organizations_url":"https://api.github.com/users/bartonjs/orgs","repos_url":"https://api.github.com/users/bartonjs/repos","events_url":"https://api.github.com/users/bartonjs/events{/privacy}","received_events_url":"https://api.github.com/users/bartonjs/received_events","type":"User","site_admin":false},"assignees":[{"login":"bartonjs","id":10642668,"avatar_url":"https://avatars3.githubusercontent.com/u/10642668?v=4","gravatar_id":"","url":"https://api.github.com/users/bartonjs","html_url":"https://github.com/bartonjs","followers_url":"https://api.github.com/users/bartonjs/followers","following_url":"https://api.github.com/users/bartonjs/following{/other_user}","gists_url":"https://api.github.com/users/bartonjs/gists{/gist_id}","starred_url":"https://api.github.com/users/bartonjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bartonjs/subscriptions","organizations_url":"https://api.github.com/users/bartonjs/orgs","repos_url":"https://api.github.com/users/bartonjs/repos","events_url":"https://api.github.com/users/bartonjs/events{/privacy}","received_events_url":"https://api.github.com/users/bartonjs/received_events","type":"User","site_admin":false}],"requested_reviewers":[{"login":"ianhays","id":2606879,"avatar_url":"https://avatars0.githubusercontent.com/u/2606879?v=4","gravatar_id":"","url":"https://api.github.com/users/ianhays","html_url":"https://github.com/ianhays","followers_url":"https://api.github.com/users/ianhays/followers","following_url":"https://api.github.com/users/ianhays/following{/other_user}","gists_url":"https://api.github.com/users/ianhays/gists{/gist_id}","starred_url":"https://api.github.com/users/ianhays/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ianhays/subscriptions","organizations_url":"https://api.github.com/users/ianhays/orgs","repos_url":"https://api.github.com/users/ianhays/repos","events_url":"https://api.github.com/users/ianhays/events{/privacy}","received_events_url":"https://api.github.com/users/ianhays/received_events","type":"User","site_admin":false}],"milestone":{"url":"https://api.github.com/repos/dotnet/corefx/milestones/12","html_url":"https://github.com/dotnet/corefx/milestone/12","labels_url":"https://api.github.com/repos/dotnet/corefx/milestones/12/labels","id":2323293,"number":12,"title":"2.1.0","description":".NET Core 2.1, next major release. See [official release dates](https://github.com/dotnet/core/blob/master/roadmap.md) for details.","creator":{"login":"karelz","id":5776068,"avatar_url":"https://avatars2.githubusercontent.com/u/5776068?v=4","gravatar_id":"","url":"https://api.github.com/users/karelz","html_url":"https://github.com/karelz","followers_url":"https://api.github.com/users/karelz/followers","following_url":"https://api.github.com/users/karelz/following{/other_user}","gists_url":"https://api.github.com/users/karelz/gists{/gist_id}","starred_url":"https://api.github.com/users/karelz/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/karelz/subscriptions","organizations_url":"https://api.github.com/users/karelz/orgs","repos_url":"https://api.github.com/users/karelz/repos","events_url":"https://api.github.com/users/karelz/events{/privacy}","received_events_url":"https://api.github.com/users/karelz/received_events","type":"User","site_admin":false},"open_issues":407,"closed_issues":3504,"state":"open","created_at":"2017-02-15T02:14:11Z","updated_at":"2017-11-22T03:22:54Z","due_on":null,"closed_at":null},"commits_url":"https://api.github.com/repos/dotnet/corefx/pulls/25296/commits","review_comments_url":"https://api.github.com/repos/dotnet/corefx/pulls/25296/comments","review_comment_url":"https://api.github.com/repos/dotnet/corefx/pulls/comments{/number}","comments_url":"https://api.github.com/repos/dotnet/corefx/issues/25296/comments","statuses_url":"https://api.github.com/repos/dotnet/corefx/statuses/951562711fb306b27fe5f34bd4e63d278f906256","head":{"label":"bartonjs:asn1-v2","ref":"asn1-v2","sha":"951562711fb306b27fe5f34bd4e63d278f906256","user":{"login":"bartonjs","id":10642668,"avatar_url":"https://avatars3.githubusercontent.com/u/10642668?v=4","gravatar_id":"","url":"https://api.github.com/users/bartonjs","html_url":"https://github.com/bartonjs","followers_url":"https://api.github.com/users/bartonjs/followers","following_url":"https://api.github.com/users/bartonjs/following{/other_user}","gists_url":"https://api.github.com/users/bartonjs/gists{/gist_id}","starred_url":"https://api.github.com/users/bartonjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bartonjs/subscriptions","organizations_url":"https://api.github.com/users/bartonjs/orgs","repos_url":"https://api.github.com/users/bartonjs/repos","events_url":"https://api.github.com/users/bartonjs/events{/privacy}","received_events_url":"https://api.github.com/users/bartonjs/received_events","type":"User","site_admin":false},"repo":{"id":29888389,"name":"corefx","full_name":"bartonjs/corefx","owner":{"login":"bartonjs","id":10642668,"avatar_url":"https://avatars3.githubusercontent.com/u/10642668?v=4","gravatar_id":"","url":"https://api.github.com/users/bartonjs","html_url":"https://github.com/bartonjs","followers_url":"https://api.github.com/users/bartonjs/followers","following_url":"https://api.github.com/users/bartonjs/following{/other_user}","gists_url":"https://api.github.com/users/bartonjs/gists{/gist_id}","starred_url":"https://api.github.com/users/bartonjs/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/bartonjs/subscriptions","organizations_url":"https://api.github.com/users/bartonjs/orgs","repos_url":"https://api.github.com/users/bartonjs/repos","events_url":"https://api.github.com/users/bartonjs/events{/privacy}","received_events_url":"https://api.github.com/users/bartonjs/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/bartonjs/corefx","description":"This repository contains the foundational libraries that make up the .NET Core development stack.","fork":true,"url":"https://api.github.com/repos/bartonjs/corefx","forks_url":"https://api.github.com/repos/bartonjs/corefx/forks","keys_url":"https://api.github.com/repos/bartonjs/corefx/keys{/key_id}","collaborators_url":"https://api.github.com/repos/bartonjs/corefx/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/bartonjs/corefx/teams","hooks_url":"https://api.github.com/repos/bartonjs/corefx/hooks","issue_events_url":"https://api.github.com/repos/bartonjs/corefx/issues/events{/number}","events_url":"https://api.github.com/repos/bartonjs/corefx/events","assignees_url":"https://api.github.com/repos/bartonjs/corefx/assignees{/user}","branches_url":"https://api.github.com/repos/bartonjs/corefx/branches{/branch}","tags_url":"https://api.github.com/repos/bartonjs/corefx/tags","blobs_url":"https://api.github.com/repos/bartonjs/corefx/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/bartonjs/corefx/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/bartonjs/corefx/git/refs{/sha}","trees_url":"https://api.github.com/repos/bartonjs/corefx/git/trees{/sha}","statuses_url":"https://api.github.com/repos/bartonjs/corefx/statuses/{sha}","languages_url":"https://api.github.com/repos/bartonjs/corefx/languages","stargazers_url":"https://api.github.com/repos/bartonjs/corefx/stargazers","contributors_url":"https://api.github.com/repos/bartonjs/corefx/contributors","subscribers_url":"https://api.github.com/repos/bartonjs/corefx/subscribers","subscription_url":"https://api.github.com/repos/bartonjs/corefx/subscription","commits_url":"https://api.github.com/repos/bartonjs/corefx/commits{/sha}","git_commits_url":"https://api.github.com/repos/bartonjs/corefx/git/commits{/sha}","comments_url":"https://api.github.com/repos/bartonjs/corefx/comments{/number}","issue_comment_url":"https://api.github.com/repos/bartonjs/corefx/issues/comments{/number}","contents_url":"https://api.github.com/repos/bartonjs/corefx/contents/{+path}","compare_url":"https://api.github.com/repos/bartonjs/corefx/compare/{base}...{head}","merges_url":"https://api.github.com/repos/bartonjs/corefx/merges","archive_url":"https://api.github.com/repos/bartonjs/corefx/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/bartonjs/corefx/downloads","issues_url":"https://api.github.com/repos/bartonjs/corefx/issues{/number}","pulls_url":"https://api.github.com/repos/bartonjs/corefx/pulls{/number}","milestones_url":"https://api.github.com/repos/bartonjs/corefx/milestones{/number}","notifications_url":"https://api.github.com/repos/bartonjs/corefx/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/bartonjs/corefx/labels{/name}","releases_url":"https://api.github.com/repos/bartonjs/corefx/releases{/id}","deployments_url":"https://api.github.com/repos/bartonjs/corefx/deployments","created_at":"2015-01-26T23:55:53Z","updated_at":"2016-10-26T14:28:39Z","pushed_at":"2017-11-21T15:26:27Z","git_url":"git://github.com/bartonjs/corefx.git","ssh_url":"git@github.com:bartonjs/corefx.git","clone_url":"https://github.com/bartonjs/corefx.git","svn_url":"https://github.com/bartonjs/corefx","homepage":"","size":161528,"stargazers_count":0,"watchers_count":0,"language":"C#","has_issues":false,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":1,"mirror_url":null,"archived":false,"open_issues_count":0,"forks":1,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"dotnet:master","ref":"master","sha":"6a9f579209491ae9041f208bfe34b89085c0279e","user":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars0.githubusercontent.com/u/9141961?v=4","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"repo":{"id":26295345,"name":"corefx","full_name":"dotnet/corefx","owner":{"login":"dotnet","id":9141961,"avatar_url":"https://avatars0.githubusercontent.com/u/9141961?v=4","gravatar_id":"","url":"https://api.github.com/users/dotnet","html_url":"https://github.com/dotnet","followers_url":"https://api.github.com/users/dotnet/followers","following_url":"https://api.github.com/users/dotnet/following{/other_user}","gists_url":"https://api.github.com/users/dotnet/gists{/gist_id}","starred_url":"https://api.github.com/users/dotnet/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/dotnet/subscriptions","organizations_url":"https://api.github.com/users/dotnet/orgs","repos_url":"https://api.github.com/users/dotnet/repos","events_url":"https://api.github.com/users/dotnet/events{/privacy}","received_events_url":"https://api.github.com/users/dotnet/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/dotnet/corefx","description":"This repo contains the .NET Core foundational libraries, called CoreFX. It includes classes for collections, file systems, console, XML, async and many others. We welcome contributions.","fork":false,"url":"https://api.github.com/repos/dotnet/corefx","forks_url":"https://api.github.com/repos/dotnet/corefx/forks","keys_url":"https://api.github.com/repos/dotnet/corefx/keys{/key_id}","collaborators_url":"https://api.github.com/repos/dotnet/corefx/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/dotnet/corefx/teams","hooks_url":"https://api.github.com/repos/dotnet/corefx/hooks","issue_events_url":"https://api.github.com/repos/dotnet/corefx/issues/events{/number}","events_url":"https://api.github.com/repos/dotnet/corefx/events","assignees_url":"https://api.github.com/repos/dotnet/corefx/assignees{/user}","branches_url":"https://api.github.com/repos/dotnet/corefx/branches{/branch}","tags_url":"https://api.github.com/repos/dotnet/corefx/tags","blobs_url":"https://api.github.com/repos/dotnet/corefx/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/dotnet/corefx/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/dotnet/corefx/git/refs{/sha}","trees_url":"https://api.github.com/repos/dotnet/corefx/git/trees{/sha}","statuses_url":"https://api.github.com/repos/dotnet/corefx/statuses/{sha}","languages_url":"https://api.github.com/repos/dotnet/corefx/languages","stargazers_url":"https://api.github.com/repos/dotnet/corefx/stargazers","contributors_url":"https://api.github.com/repos/dotnet/corefx/contributors","subscribers_url":"https://api.github.com/repos/dotnet/corefx/subscribers","subscription_url":"https://api.github.com/repos/dotnet/corefx/subscription","commits_url":"https://api.github.com/repos/dotnet/corefx/commits{/sha}","git_commits_url":"https://api.github.com/repos/dotnet/corefx/git/commits{/sha}","comments_url":"https://api.github.com/repos/dotnet/corefx/comments{/number}","issue_comment_url":"https://api.github.com/repos/dotnet/corefx/issues/comments{/number}","contents_url":"https://api.github.com/repos/dotnet/corefx/contents/{+path}","compare_url":"https://api.github.com/repos/dotnet/corefx/compare/{base}...{head}","merges_url":"https://api.github.com/repos/dotnet/corefx/merges","archive_url":"https://api.github.com/repos/dotnet/corefx/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/dotnet/corefx/downloads","issues_url":"https://api.github.com/repos/dotnet/corefx/issues{/number}","pulls_url":"https://api.github.com/repos/dotnet/corefx/pulls{/number}","milestones_url":"https://api.github.com/repos/dotnet/corefx/milestones{/number}","notifications_url":"https://api.github.com/repos/dotnet/corefx/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/dotnet/corefx/labels{/name}","releases_url":"https://api.github.com/repos/dotnet/corefx/releases{/id}","deployments_url":"https://api.github.com/repos/dotnet/corefx/deployments","created_at":"2014-11-06T23:42:48Z","updated_at":"2017-11-22T03:18:33Z","pushed_at":"2017-11-22T03:28:40Z","git_url":"git://github.com/dotnet/corefx.git","ssh_url":"git@github.com:dotnet/corefx.git","clone_url":"https://github.com/dotnet/corefx.git","svn_url":"https://github.com/dotnet/corefx","homepage":"https://github.com/dotnet/core","size":162019,"stargazers_count":12895,"watchers_count":12895,"language":"C#","has_issues":true,"has_projects":true,"has_downloads":true,"has_wiki":true,"has_pages":false,"forks_count":3609,"mirror_url":null,"archived":false,"open_issues_count":2177,"forks":3609,"open_issues":2177,"watchers":12895,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/25296"},"html":{"href":"https://github.com/dotnet/corefx/pull/25296"},"issue":{"href":"https://api.github.com/repos/dotnet/corefx/issues/25296"},"comments":{"href":"https://api.github.com/repos/dotnet/corefx/issues/25296/comments"},"review_comments":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/25296/comments"},"review_comment":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/dotnet/corefx/pulls/25296/commits"},"statuses":{"href":"https://api.github.com/repos/dotnet/corefx/statuses/951562711fb306b27fe5f34bd4e63d278f906256"}},"author_association":"MEMBER"}}
{"actor":{"display_login":"GrabYourPitchforks"}}