Remove last usages of DerSequenceReader/DerEncoder/AsnSerializer
authorFilip Navara <filip.navara@gmail.com>
Mon, 10 Sep 2018 21:42:56 +0000 (23:42 +0200)
committerJeremy Barton <jbarton@microsoft.com>
Mon, 10 Sep 2018 21:42:56 +0000 (14:42 -0700)
* Convert remainder of S.S.C.X509Certificates to use ASNXML/AsnReader/AsnWriter instead of DerSequenceReader/DerEncoder.

* Convert X509ExtensionAsn to code generator. Remove last usages of ASN serializer from code base.

* Remove DerEncoder, DerSequenceReader and related tests.

Commit migrated from https://github.com/dotnet/corefx/commit/4630572a4af4326f2d8bf983a5dc346d25c5238b

40 files changed:
src/libraries/Common/src/Interop/Unix/System.Security.Cryptography.Native/Interop.ASN1.GetIntegerBytes.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.manual.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.cs [deleted file]
src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.manual.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml.cs [new file with mode: 0644]
src/libraries/Common/src/System/Security/Cryptography/DerEncoder.cs [deleted file]
src/libraries/Common/src/System/Security/Cryptography/DerSequenceReader.cs [deleted file]
src/libraries/System.Security.Cryptography.Encoding/tests/DerEncoderTests.cs [deleted file]
src/libraries/System.Security.Cryptography.Encoding/tests/DerSequenceReaderTests.cs [deleted file]
src/libraries/System.Security.Cryptography.Encoding/tests/System.Security.Cryptography.Encoding.Tests.csproj
src/libraries/System.Security.Cryptography.Pkcs/src/Resources/Strings.resx
src/libraries/System.Security.Cryptography.Pkcs/src/System.Security.Cryptography.Pkcs.csproj
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampTokenInfo.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Helpers.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.OSX/CertificateData.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/CertificatePolicy.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/CrlCache.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/ManagedCertificateFinder.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509ChainProcessor.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/OpenSslX509Encoder.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/X500NameEncoder.ManagedDecode.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Resources/Strings.resx
src/libraries/System.Security.Cryptography.X509Certificates/src/System.Security.Cryptography.X509Certificates.csproj
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/AccessDescriptionAsn.xml [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/AccessDescriptionAsn.xml.cs [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificatePolicyMappingAsn.xml [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificatePolicyMappingAsn.xml.cs [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificateTemplateAsn.xml [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificateTemplateAsn.xml.cs [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointAsn.xml [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointAsn.xml.cs [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointNameAsn.xml [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointNameAsn.xml.cs [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyConstraintsAsn.xml [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyConstraintsAsn.xml.cs [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyInformationAsn.xml [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyInformationAsn.xml.cs [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/ReasonFlagsAsn.cs [new file with mode: 0644]
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/CertificateRequest.cs

index 692abb2..0686229 100644 (file)
@@ -6,6 +6,7 @@ using System;
 using System.Diagnostics;
 using System.Runtime.InteropServices;
 using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
 using System.Text;
 
 using Microsoft.Win32.SafeHandles;
@@ -38,8 +39,8 @@ internal static partial class Interop
                 (handle, buf) => EncodeAsn1Integer(handle, buf),
                 asn1Integer);
 
-            DerSequenceReader reader = DerSequenceReader.CreateForPayload(derEncoded);
-            return reader.ReadIntegerBytes();
+            AsnReader reader = new AsnReader(derEncoded, AsnEncodingRules.DER);
+            return reader.GetIntegerBytes().ToArray();
         }
     }
 }
index d0cbd46..9a59973 100644 (file)
@@ -6,8 +6,8 @@ using System.Runtime.InteropServices;
 
 namespace System.Security.Cryptography.Asn1
 {
-       internal partial struct AlgorithmIdentifierAsn
-       {
+    internal partial struct AlgorithmIdentifierAsn
+    {
         internal static readonly ReadOnlyMemory<byte> ExplicitDerNull = new byte[] { 0x05, 0x00 };
 
         internal bool Equals(ref AlgorithmIdentifierAsn other)
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.cs
deleted file mode 100644 (file)
index 1477a76..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Runtime.InteropServices;
-using System.Security.Cryptography.X509Certificates;
-using Internal.Cryptography;
-
-namespace System.Security.Cryptography.Asn1
-{
-    [StructLayout(LayoutKind.Sequential)]
-    internal partial struct X509ExtensionAsn
-    {
-        [ObjectIdentifier]
-        internal string ExtnId;
-
-        [DefaultValue(0x01, 0x01, 0x00)]
-        internal bool Critical;
-
-        [OctetString]
-        internal ReadOnlyMemory<byte> ExtnValue;
-
-        public X509ExtensionAsn(X509Extension extension, bool copyValue=true)
-        {
-            if (extension == null)
-            {
-                throw new ArgumentNullException(nameof(extension));
-            }
-
-            ExtnId = extension.Oid.Value;
-            Critical = extension.Critical;
-            ExtnValue = copyValue ? extension.RawData.CloneByteArray() : extension.RawData;
-        }
-
-        internal void Encode(AsnWriter writer)
-        {
-            AsnSerializer.Serialize(this, writer);
-        }
-
-        internal static void Decode(AsnReader reader, out X509ExtensionAsn decoded)
-        {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            ReadOnlyMemory<byte> value = reader.GetEncodedValue();
-            decoded = AsnSerializer.Deserialize<X509ExtensionAsn>(value, reader.RuleSet);
-        }
-    }
-}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.manual.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.manual.cs
new file mode 100644 (file)
index 0000000..0fcd8c2
--- /dev/null
@@ -0,0 +1,24 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Runtime.InteropServices;
+using System.Security.Cryptography.X509Certificates;
+
+namespace System.Security.Cryptography.Asn1
+{
+    internal partial struct X509ExtensionAsn
+    {
+        public X509ExtensionAsn(X509Extension extension)
+        {
+            if (extension == null)
+            {
+                throw new ArgumentNullException(nameof(extension));
+            }
+
+            ExtnId = extension.Oid;
+            Critical = extension.Critical;
+            ExtnValue = extension.RawData;
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml
new file mode 100644 (file)
index 0000000..0bf07c6
--- /dev/null
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="X509ExtensionAsn"
+  namespace="System.Security.Cryptography.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc5280#section-4.1
+
+    Extension ::= SEQUENCE {
+        extnID      OBJECT IDENTIFIER,
+        critical    BOOLEAN DEFAULT FALSE,
+        extnValue   OCTET STRING
+                    - contains the DER encoding of an ASN.1 value
+                    - corresponding to the extension type identified
+                    - by extnID
+    }
+  -->
+  <asn:ObjectIdentifier name="ExtnId" />
+  <asn:Boolean name="Critical" defaultDerInit="0x01, 0x01, 0x00" />
+  <asn:OctetString name="ExtnValue" />
+</asn:Sequence>
diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml.cs
new file mode 100644 (file)
index 0000000..9abbe1d
--- /dev/null
@@ -0,0 +1,115 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct X509ExtensionAsn
+    {
+        private static byte[] s_defaultCritical = { 0x01, 0x01, 0x00 };
+  
+        internal Oid ExtnId;
+        internal bool Critical;
+        internal ReadOnlyMemory<byte> ExtnValue;
+      
+#if DEBUG  
+        static X509ExtensionAsn()
+        {
+            X509ExtensionAsn decoded = default;
+            AsnReader reader;
+
+            reader = new AsnReader(s_defaultCritical, AsnEncodingRules.DER);
+            decoded.Critical = reader.ReadBoolean();
+            reader.ThrowIfNotEmpty();
+        }
+#endif
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteObjectIdentifier(ExtnId);
+        
+            // DEFAULT value handler for Critical.
+            {
+                using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
+                {
+                    tmp.WriteBoolean(Critical);
+                    ReadOnlySpan<byte> encoded = tmp.EncodeAsSpan();
+
+                    if (!encoded.SequenceEqual(s_defaultCritical))
+                    {
+                        writer.WriteEncodedValue(encoded.ToArray());
+                    }
+                }
+            }
+
+            writer.WriteOctetString(ExtnValue.Span);
+            writer.PopSequence(tag);
+        }
+
+        internal static X509ExtensionAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static X509ExtensionAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out X509ExtensionAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out X509ExtensionAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out X509ExtensionAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnReader defaultReader;
+            
+            decoded.ExtnId = sequenceReader.ReadObjectIdentifier();
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Boolean))
+            {
+                decoded.Critical = sequenceReader.ReadBoolean();
+            }
+            else
+            {
+                defaultReader = new AsnReader(s_defaultCritical, AsnEncodingRules.DER);
+                decoded.Critical = defaultReader.ReadBoolean();
+            }
+
+
+            if (sequenceReader.TryGetPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpExtnValue))
+            {
+                decoded.ExtnValue = tmpExtnValue;
+            }
+            else
+            {
+                decoded.ExtnValue = sequenceReader.ReadOctetString();
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/DerEncoder.cs b/src/libraries/Common/src/System/Security/Cryptography/DerEncoder.cs
deleted file mode 100644 (file)
index bf9dca7..0000000
+++ /dev/null
@@ -1,1148 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Collections;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Numerics;
-using System.Text;
-
-namespace System.Security.Cryptography
-{
-    /// <summary>
-    /// Writes data encoded via the Distinguished Encoding Rules for Abstract
-    /// Syntax Notation 1 (ASN.1) data.
-    /// </summary>
-    internal static class DerEncoder
-    {
-        private const byte ConstructedFlag = 0x20;
-        private const byte ConstructedSequenceTag = ConstructedFlag | (byte)DerSequenceReader.DerTag.Sequence;
-        private const byte ConstructedSetTag = ConstructedFlag | (byte)DerSequenceReader.DerTag.Set;
-
-        private static readonly byte[][] s_nullTlv =
-        {
-            new byte[] { (byte)DerSequenceReader.DerTag.Null },
-            new byte[] { 0 },
-            Array.Empty<byte>(),
-        };
-
-        private static byte[] EncodeLength(int length)
-        {
-            Debug.Assert(length >= 0);
-
-            byte low = unchecked((byte)length);
-            
-            // If the length value fits in 7 bits, it's an answer all by itself.
-            if (length < 0x80)
-            {
-                return new[] { low };
-            }
-
-            // If the length is more than 0x7F then it is stored as
-            // 0x80 | lengthLength
-            // big
-            // endian
-            // length
-
-            // So:
-            // 0 => 0x00.
-            // 1 => 0x01.
-            // 127 => 0x7F.
-            // 128 => 0x81 0x80
-            // 255 => 0x81 0xFF
-            // 256 => 0x82 0x01 0x00
-            // 65535 => 0x82 0xFF 0xFF
-            // 65536 => 0x83 0x01 0x00 0x00
-            // ...
-            // int.MaxValue => 0x84 0x7F 0xFF 0xFF 0xFF
-            //
-            // Technically DER lengths can go longer than int.MaxValue, but since our
-            // encoding input here is an int, our output will be no larger than that.
-
-            if (length <= 0xFF)
-            {
-                return new byte[] { 0x81, low };
-            }
-
-            int remainder = length >> 8;
-            byte midLow = unchecked((byte)remainder);
-
-            if (length <= 0xFFFF)
-            {
-                return new byte[] { 0x82, midLow, low };
-            }
-
-            remainder >>= 8;
-            byte midHigh = unchecked((byte)remainder);
-
-            if (length <= 0xFFFFFF)
-            {
-                return new byte[] { 0x83, midHigh, midLow, low };
-            }
-
-            remainder >>= 8;
-            byte high = unchecked((byte)remainder);
-
-            // Since we know this was a non-negative signed number, the highest
-            // legal value here is 0x7F.
-            Debug.Assert(remainder < 0x80);
-
-            return new byte[] { 0x84, high, midHigh, midLow, low };
-        }
-
-        /// <summary>
-        /// Encode the segments { tag, length, value } of a boolean.
-        /// </summary>
-        /// <param name="value">The boolean to encode</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodeBoolean(bool value)
-        {
-            // BER says FALSE is zero, TRUE is other.
-            // DER says TRUE is 0xFF.
-            byte[] data =
-            {
-                (byte)(value ? 0xFF : 0x00),
-            };
-
-            return new byte[][]
-            {
-                new byte[] { (byte)DerSequenceReader.DerTag.Boolean }, 
-                new byte[] { 0x01 }, 
-                data, 
-            };
-        }
-
-        /// <summary>
-        /// Encode the segments { tag, length, value } of an unsigned integer.
-        /// </summary>
-        /// <param name="value">The value to encode.</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodeUnsignedInteger(uint value)
-        {
-            byte[] bytes = BitConverter.GetBytes(value);
-
-            if (BitConverter.IsLittleEndian)
-            {
-                Array.Reverse(bytes);
-            }
-
-            return SegmentedEncodeUnsignedInteger(bytes);
-        }
-
-        /// <summary>
-        /// Encode the segments { tag, length, value } of an unsigned integer.
-        /// </summary>
-        /// <param name="bigEndianBytes">The value to encode, in big integer representation.</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodeUnsignedInteger(ReadOnlySpan<byte> bigEndianBytes)
-        {
-            Debug.Assert(!bigEndianBytes.IsEmpty, "The span must not be empty.");
-
-            int start = 0;
-            int end = start + bigEndianBytes.Length;
-
-            // Remove any leading zeroes.
-            while (start < end && bigEndianBytes[start] == 0)
-            {
-                start++;
-            }
-
-            // All zeroes, just back up one and let it flow through the normal flow.
-            if (start == end)
-            {
-                start--;
-                Debug.Assert(start >= 0);
-            }
-
-            // If the first byte is bigger than 0x7F it will look like a negative number, since
-            // we're unsigned, insert a zero-padding byte.
-            int length = end - start;
-            int writeStart = bigEndianBytes[start] > 0x7F ? 1 : 0;
-            var dataBytes = new byte[length + writeStart];
-            bigEndianBytes.Slice(start, length).CopyTo(new Span<byte>(dataBytes).Slice(writeStart));
-
-            return new[]
-            {
-                new[] { (byte)DerSequenceReader.DerTag.Integer },
-                EncodeLength(dataBytes.Length),
-                dataBytes,
-            };
-        }
-
-        /// <summary>
-        /// Encode the segments { tag, length, value } of a BIT STRING which is wrapped over
-        /// other DER-encoded data.
-        /// </summary>
-        /// <param name="childSegments"></param>
-        /// <remarks>
-        /// Despite containing other DER-encoded data this does not get the constructed bit,
-        /// because it doesn't when encoding public keys in SubjectPublicKeyInfo</remarks>
-        /// <returns></returns>
-        internal static byte[][] SegmentedEncodeBitString(params byte[][][] childSegments)
-        {
-            return SegmentedEncodeBitString(ConcatenateArrays(childSegments));
-        }
-
-        /// <summary>
-        /// Encode the segments { tag, length, value } of a bit string where all bits are significant.
-        /// </summary>
-        /// <param name="data">The data to encode</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodeBitString(byte[] data)
-        {
-            return SegmentedEncodeBitString(0, data);
-        }
-
-        /// <summary>
-        /// Encode the segments { tag, length, value } of a bit string where the least significant
-        /// <paramref name="unusedBits"/> of the last byte are padding.
-        /// </summary>
-        /// <param name="unusedBits">The number of padding bits (0-7) in the last byte</param>
-        /// <param name="data">The data to encode</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodeBitString(int unusedBits, byte[] data)
-        {
-            Debug.Assert(data != null);
-            Debug.Assert(unusedBits >= 0);
-            Debug.Assert(unusedBits <= 7);
-            Debug.Assert(unusedBits == 0 || data.Length > 0);
-
-            byte[] encodedData = new byte[data.Length + 1];
-
-            // Copy data to encodedData, but leave a one byte gap for unusedBits.
-            Buffer.BlockCopy(data, 0, encodedData, 1, data.Length);
-            encodedData[0] = (byte)unusedBits;
-
-            // We need to make a mask of the bits to keep around for the last
-            // byte, ensuring we clear out any bits that were set, but reported
-            // as padding by unusedBits
-            // 
-            // For example:
-            // unusedBits 0 => mask 0b11111111
-            // unusedBits 1 => mask 0b11111110
-            // unusedBits 7 => mask 0b10000000
-            byte lastByteSemanticMask = unchecked((byte)(-1 << unusedBits));
-
-            // Since encodedData.Length is data.Length + 1, "encodedDate.Length - 1" is just "data.Length".
-            encodedData[data.Length] &= lastByteSemanticMask;
-
-            return new byte[][]
-            {
-                new byte[] { (byte)DerSequenceReader.DerTag.BitString },
-                EncodeLength(encodedData.Length),
-                encodedData,
-            };
-        }
-
-        /// <summary>
-        /// Encode the segments { tag, length, value } of a bit string value based upon a NamedBitList.
-        /// ((<paramref name="bigEndianBytes"/>[0] >> 7) &amp; 1) is considered the "leading" bit, proceeding
-        /// through the array for up to <paramref name="namedBitsCount"/>.
-        /// </summary>
-        /// <param name="bigEndianBytes">
-        /// The data in big endian order, the most significant bit of byte 0 is the leading bit
-        /// (corresponds to the named value for "bit 0"). Any bits beyond <paramref name="namedBitsCount"/>
-        /// are ignored, and any missing bits are assumed to be unset.
-        /// </param>
-        /// <param name="namedBitsCount">
-        /// The total number of named bits.  Since the bits are numbered with a zero index, this should be
-        /// one higher than the largest defined bit. (namedBitsCount=10 covers bits 0-9)
-        /// </param>
-        /// <returns>
-        /// A triplet of { tag }, { length }, { data }.  All trailing unset named bits are removed. 
-        /// </returns>
-        internal static byte[][] SegmentedEncodeNamedBitList(byte[] bigEndianBytes, int namedBitsCount)
-        {
-            Debug.Assert(bigEndianBytes != null, "bigEndianBytes != null");
-            Debug.Assert(namedBitsCount > 0, "namedBitsCount > 0");
-
-            // The encoding that this follows is the DER encoding for NamedBitList, which is different than
-            // (unnamed) BIT STRING.
-            //
-            // X.690 (08/2015) section 11.2.2 (Unused bits) says:
-            //    Where ITU-T Rec. X.680 | ISO/IEC 8824-1, 22.7, applies, the bitstring shall have all
-            //    trailing 0 bits removed before it is encoded.
-            //        NOTE 1 – In the case where a size constraint has been applied, the abstract value
-            //            delivered by a decoder to the application will be one of those satisfying the
-            //            size constraint and differing from the transmitted value only in the number of
-            //            trailing 0 bits.
-            //        NOTE 2 – If a bitstring value has no 1 bits, then an encoder shall encode the value
-            //            with a length of 1 and an initial octet set to 0.
-            //
-            // X.680 (08/2015) section 22.7 says:
-            //    When a "NamedBitList" is used in defining a bitstring type ASN.1 encoding rules are free
-            //    to add (or remove) arbitrarily any trailing 0 bits to (or from) values that are being
-            //    encoded or decoded
-            //
-            // Therefore, if 16 bits are defined, and only bit 7 is set, instead of { 00 01 00 } the encoding
-            // should be { 00 01 }
-            //
-            // And, if 8 bits are defined, and only bit 6 is set, instead of { 00 02 } it should be { 01 02 },
-            // signifying that the last bit was omitted.
-
-            int lastSetBit = -1;
-
-            int lastBitProvided = (bigEndianBytes.Length * 8) - 1;
-            int lastPossibleBit = Math.Min(lastBitProvided, namedBitsCount - 1);
-
-            for (int currentBit = lastPossibleBit; currentBit >= 0; currentBit--)
-            {
-                int currentByte = currentBit / 8;
-
-                // As we loop through the numbered bits we need to figure out
-                // 1) which indexed byte it would be in (currentByte)
-                // 2) How many bits from the right it is (shiftIndex)
-                // 
-                // For example:
-                // currentBit 0 => currentByte 0, shiftIndex 7 (1 << 7)
-                // currentBit 1 => currentByte 0, shiftIndex 6 (1 << 6)
-                // currentBit 7 => currentByte 0, shiftIndex 0 (1 << 0)
-                // currentBit 8 => currentByte 1, shiftIndex 7 (1 << 7)
-                // etc
-                int shiftIndex = 7 - (currentBit % 8);
-                int testValue = 1 << shiftIndex;
-                byte dataByte = bigEndianBytes[currentByte];
-
-                if ((dataByte & testValue) == testValue)
-                {
-                    lastSetBit = currentBit;
-                    break;
-                }
-            }
-
-            byte[] dataSegment;
-
-            if (lastSetBit >= 0)
-            {
-                // Bits are zero-indexed, so lastSetBit=0 means "1 semantic bit", and
-                // "1 semantic bit" requires a byte to write it down.
-                int semanticBits = lastSetBit + 1;
-                int semanticBytes = (7 + semanticBits) / 8;
-
-                // For a lastSetBit of  : 0 1 2 3 4 5 6 7 8 9 A B C D E F
-                // unused bits should be: 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0
-                int unusedBits = 7 - (lastSetBit % 8);
-
-                // We need to make a mask of the bits to keep around for the last
-                // byte, ensuring we clear out any bits that were set, but beyond
-                // the namedBitsCount limit.
-                // 
-                // For example:
-                // lastSetBit 0 => mask 0b10000000
-                // lastSetBit 1 => mask 0b11000000
-                // lastSetBit 7 => mask 0b11111111
-                // lastSetBit 8 => mask 0b10000000
-                byte lastByteSemanticMask = unchecked((byte)(-1 << unusedBits));
-
-                // Semantic bytes plus the "how many unused bits" prefix byte.
-                dataSegment = new byte[semanticBytes + 1];
-                dataSegment[0] = (byte)unusedBits;
-                
-                Debug.Assert(semanticBytes <= bigEndianBytes.Length);
-
-                Buffer.BlockCopy(bigEndianBytes, 0, dataSegment, 1, semanticBytes);
-
-                // But the last byte might have too many bits set, trim it down
-                // to only the ones we knew about (all "don't care" values must be 0)
-                dataSegment[semanticBytes] &= lastByteSemanticMask;
-            }
-            else
-            {
-                // No bits being set is encoded as just "no unused bits",
-                // with no semantic payload.
-                dataSegment = new byte[] { 0x00 };
-            }
-
-            return new byte[][]
-            {
-                new byte[] { (byte)DerSequenceReader.DerTag.BitString },
-                EncodeLength(dataSegment.Length),
-                dataSegment
-            };
-        }
-
-        /// <summary>
-        /// Encode the segments { tag, length, value } of an octet string (byte array).
-        /// </summary>
-        /// <param name="data">The data to encode</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodeOctetString(byte[] data)
-        {
-            Debug.Assert(data != null);
-
-            // Because this is not currently public API the data array is not being cloned.
-            return new byte[][]
-            {
-                new byte[] { (byte)DerSequenceReader.DerTag.OctetString }, 
-                EncodeLength(data.Length),
-                data,
-            };
-        }
-
-        internal static byte[][] SegmentedEncodeNull()
-        {
-            return s_nullTlv;
-        }
-
-        /// <summary>
-        /// Encode an object identifier (Oid).
-        /// </summary>
-        /// <returns>The encoded OID</returns>
-        internal static byte[] EncodeOid(string oidValue)
-        {
-            return ConcatenateArrays(SegmentedEncodeOid(oidValue));
-        }
-
-        /// <summary>
-        /// Encode the segments { tag, length, value } of an object identifier (Oid).
-        /// </summary>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodeOid(Oid oid)
-        {
-            Debug.Assert(oid != null);
-
-            // All exceptions past this point should just be "CryptographicException", because that's
-            // how they'd come back from Desktop/Windows, since it was a non-success result of calling
-            // CryptEncodeObject.
-            string oidValue = oid.Value;
-
-            return SegmentedEncodeOid(oidValue);
-        }
-
-        /// <summary>
-        /// Encode the segments { tag, length, value } of an object identifier (Oid).
-        /// </summary>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodeOid(string oidValue)
-        {
-            // All exceptions herein should just be "CryptographicException", because that's
-            // how they'd come back from Desktop/Windows, since it was a non-success result of calling
-            // CryptEncodeObject.
-
-            if (string.IsNullOrEmpty(oidValue))
-                throw new CryptographicException(SR.Argument_InvalidOidValue);
-            if (oidValue.Length < 3 /* "1.1" is the shortest value */)
-                throw new CryptographicException(SR.Argument_InvalidOidValue);
-            if (oidValue[1] != '.')
-                throw new CryptographicException(SR.Argument_InvalidOidValue);
-
-            int firstRid;
-
-            switch (oidValue[0])
-            {
-                case '0':
-                    firstRid = 0;
-                    break;
-                case '1':
-                    firstRid = 1;
-                    break;
-                case '2':
-                    firstRid = 2;
-                    break;
-                default:
-                    throw new CryptographicException(SR.Argument_InvalidOidValue);
-            }
-
-            int startPos = 2;
-
-            // The first two RIDs are special:
-            // ITU X.690 8.19.4:
-            //   The numerical value of the first subidentifier is derived from the values of the first two
-            //   object identifier components in the object identifier value being encoded, using the formula:
-            //       (X*40) + Y
-            //   where X is the value of the first object identifier component and Y is the value of the
-            //   second object identifier component.
-            //       NOTE – This packing of the first two object identifier components recognizes that only
-            //          three values are allocated from the root node, and at most 39 subsequent values from
-            //          nodes reached by X = 0 and X = 1.
-
-            BigInteger rid = ParseOidRid(oidValue, ref startPos);
-            rid += 40 * firstRid;
-
-            // The worst case is "1.1.1.1.1", which takes 4 bytes (5 rids, with the first two condensed)
-            // Longer numbers get smaller: "2.1.127" is only 2 bytes. (81d (0x51) and 127 (0x7F))
-            // So length / 2 should prevent any reallocations.
-            List<byte> encodedBytes = new List<byte>(oidValue.Length / 2);
-
-            EncodeRid(encodedBytes, ref rid);
-
-            while (startPos < oidValue.Length)
-            {
-                rid = ParseOidRid(oidValue, ref startPos);
-
-                EncodeRid(encodedBytes, ref rid);
-            }
-
-            return new byte[][]
-            {
-                new byte[] { (byte)DerSequenceReader.DerTag.ObjectIdentifier }, 
-                EncodeLength(encodedBytes.Count),
-                encodedBytes.ToArray(),
-            };
-        }
-
-        /// <summary>
-        /// Encode a character string as a UTF8String value.
-        /// </summary>
-        /// <param name="chars">The characters to be encoded.</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodeUtf8String(char[] chars)
-        {
-            Debug.Assert(chars != null);
-
-            return SegmentedEncodeUtf8String(chars, 0, chars.Length);
-        }
-
-        /// <summary>
-        /// Encode a substring as a UTF8String value.
-        /// </summary>
-        /// <param name="chars">The characters whose substring is to be encoded.</param>
-        /// <param name="offset">The character offset into <paramref name="chars"/> at which to start.</param>
-        /// <param name="count">The total number of characters from <paramref name="chars"/> to read.</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodeUtf8String(char[] chars, int offset, int count)
-        {
-            Debug.Assert(chars != null);
-            Debug.Assert(offset >= 0);
-            Debug.Assert(offset <= chars.Length);
-            Debug.Assert(count >= 0);
-            Debug.Assert(count <= chars.Length - offset);
-
-            // ITU-T X.690 says that ISO/IEC 10646 Annex D should be used; but no announcers
-            // or escape sequences, and each character shall be encoded in the smallest number of
-            // bytes possible.
-            //
-            // Thankfully, that's just Encoding.UTF8.
-
-            byte[] encodedBytes = System.Text.Encoding.UTF8.GetBytes(chars, offset, count);
-
-            return new byte[][]
-            {
-                new byte[] { (byte)DerSequenceReader.DerTag.UTF8String },
-                EncodeLength(encodedBytes.Length),
-                encodedBytes,
-            };
-        }
-
-        /// <summary>
-        /// Make a constructed SEQUENCE of the byte-triplets of the contents, but leave
-        /// the value in a segmented form (to be included in a larger SEQUENCE).
-        /// </summary>
-        /// <param name="items">Series of Tag-Length-Value triplets to build into one sequence.</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] ConstructSegmentedSequence(params byte[][][] items)
-        {
-            return ConstructSegmentedSequence((IEnumerable<byte[][]>)items);
-        }
-
-        internal static byte[][] ConstructSegmentedSequence(IEnumerable<byte[][]> items)
-        {
-            Debug.Assert(items != null);
-
-            byte[] data = ConcatenateArrays(items);
-
-            return new byte[][]
-            {
-                new byte[] { ConstructedSequenceTag }, 
-                EncodeLength(data.Length),
-                data,
-            };
-        }
-
-        /// <summary>
-        /// Make a context-specific tagged value which is constructed of other DER encoded values.
-        /// Logically the same as a SEQUENCE, but providing context as to data interpretation (and usually
-        /// indicates an optional element adjacent to another SEQUENCE).
-        /// </summary>
-        /// <param name="contextId">The value's context ID</param>
-        /// <param name="items">Series of Tag-Length-Value triplets to build into one sequence.</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] ConstructSegmentedContextSpecificValue(int contextId, params byte[][][] items)
-        {
-            Debug.Assert(items != null);
-            Debug.Assert(contextId >= 0 && contextId <= 30);
-
-            byte[] data = ConcatenateArrays(items);
-
-            byte tagId = (byte)(
-                DerSequenceReader.ConstructedFlag |
-                DerSequenceReader.ContextSpecificTagFlag |
-                contextId);
-
-            return new byte[][]
-            {
-                new byte[] { tagId },
-                EncodeLength(data.Length),
-                data,
-            };
-        }
-
-        /// <summary>
-        /// Make a constructed SET of the byte-triplets of the contents, but leave
-        /// the value in a segmented form (to be included in a larger SEQUENCE).
-        /// </summary>
-        /// <param name="items">Series of Tag-Length-Value triplets to build into one set.</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] ConstructSegmentedSet(params byte[][][] items)
-        {
-            Debug.Assert(items != null);
-
-            byte[][][] sortedItems = (byte[][][])items.Clone();
-            Array.Sort(sortedItems, AsnSetValueComparer.Instance);
-            byte[] data = ConcatenateArrays(sortedItems);
-
-            return new byte[][]
-            {
-                new byte[] { ConstructedSetTag },
-                EncodeLength(data.Length),
-                data,
-            };
-        }
-
-        /// <summary>
-        /// Make a constructed SET of the byte-triplets of the contents, but leave
-        /// the value in a segmented form (to be included in a larger SEQUENCE).
-        /// 
-        /// This method assumes that the data is presorted, and writes it as-is.
-        /// </summary>
-        /// <param name="items">Series of Tag-Length-Value triplets to build into one set.</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] ConstructSegmentedPresortedSet(params byte[][][] items)
-        {
-            Debug.Assert(items != null);
-
-            byte[] data = ConcatenateArrays(items);
-
-            return new byte[][]
-            {
-                new byte[] { ConstructedSetTag },
-                EncodeLength(data.Length),
-                data,
-            };
-        }
-
-        /// <summary>
-        /// Test to see if the input characters contains only characters permitted by the ASN.1
-        /// PrintableString restricted character set.
-        /// </summary>
-        /// <param name="chars">The characters to test.</param>
-        /// <returns>
-        /// <c>true</c> if all of the characters in <paramref name="chars"/> are valid PrintableString characters,
-        /// <c>false</c> otherwise.
-        /// </returns>
-        internal static bool IsValidPrintableString(char[] chars)
-        {
-            Debug.Assert(chars != null);
-
-            return IsValidPrintableString(chars, 0, chars.Length);
-        }
-
-        /// <summary>
-        /// Test to see if the input substring contains only characters permitted by the ASN.1
-        /// PrintableString restricted character set.
-        /// </summary>
-        /// <param name="chars">The character string to test.</param>
-        /// <param name="offset">The starting character position within <paramref name="chars"/>.</param>
-        /// <param name="count">The number of characters from <paramref name="chars"/> to read.</param>
-        /// <returns>
-        /// <c>true</c> if all of the indexed characters in <paramref name="chars"/> are valid PrintableString
-        /// characters, <c>false</c> otherwise.
-        /// </returns>
-        internal static bool IsValidPrintableString(char[] chars, int offset, int count)
-        {
-            Debug.Assert(chars != null);
-            Debug.Assert(offset >= 0);
-            Debug.Assert(offset <= chars.Length);
-            Debug.Assert(count >= 0);
-            Debug.Assert(count <= chars.Length - offset);
-
-            int end = count + offset;
-
-            for (int i = offset; i < end; i++)
-            {
-                if (!IsPrintableStringCharacter(chars[i]))
-                {
-                    return false;
-                }
-            }
-
-            return true;
-        }
-
-        /// <summary>
-        /// Encode a character string as a PrintableString value.
-        /// </summary>
-        /// <param name="chars">The characters to be encoded.</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodePrintableString(char[] chars)
-        {
-            Debug.Assert(chars != null);
-
-            return SegmentedEncodePrintableString(chars, 0, chars.Length);
-        }
-
-        /// <summary>
-        /// Encode a substring as a PrintableString value.
-        /// </summary>
-        /// <param name="chars">The character string whose substring is to be encoded.</param>
-        /// <param name="offset">The character offset into <paramref name="chars"/> at which to start.</param>
-        /// <param name="count">The total number of characters from <paramref name="chars"/> to read.</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodePrintableString(char[] chars, int offset, int count)
-        {
-            Debug.Assert(chars != null);
-            Debug.Assert(offset >= 0);
-            Debug.Assert(offset <= chars.Length);
-            Debug.Assert(count >= 0);
-            Debug.Assert(count <= chars.Length);
-            Debug.Assert(offset + count <= chars.Length);
-
-            Debug.Assert(IsValidPrintableString(chars, offset, count));
-
-            // ITU-T X.690 (08/2015) 8.23.5 says to encode PrintableString as ISO/IEC 2022 using an implicit
-            // context of G0=6 (ANSI/ASCII) and no explicit escape sequences are allowed.
-            //
-            // That's a long-winded way of saying that it's just ASCII.  Since we've already established
-            // that it fits the PrintableString character restrictions, we can just convert char to byte.
-            byte[] encodedString = new byte[count];
-
-            for (int i = 0; i < count; i++)
-            {
-                encodedString[i] = (byte)chars[i + offset];
-            }
-
-            return new byte[][]
-            {
-                new byte[] { (byte)DerSequenceReader.DerTag.PrintableString },
-                EncodeLength(encodedString.Length),
-                encodedString,
-            };
-        }
-
-        /// <summary>
-        /// Encode a string of characters as a IA5String value.
-        /// </summary>
-        /// <param name="chars">The characters to be encoded.</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodeIA5String(char[] chars)
-        {
-            Debug.Assert(chars != null);
-
-            return SegmentedEncodeIA5String(chars, 0, chars.Length);
-        }
-
-        /// <summary>
-        /// Encode a substring as a IA5String value.
-        /// </summary>
-        /// <param name="chars">The characters whose substring is to be encoded.</param>
-        /// <param name="offset">The character offset into <paramref name="chars"/> at which to start.</param>
-        /// <param name="count">The total number of characters from <paramref name="chars"/> to read.</param>
-        /// <returns>The encoded segments { tag, length, value }</returns>
-        internal static byte[][] SegmentedEncodeIA5String(char[] chars, int offset, int count)
-        {
-            Debug.Assert(chars != null);
-            Debug.Assert(offset >= 0);
-            Debug.Assert(offset <= chars.Length);
-            Debug.Assert(count >= 0);
-            Debug.Assert(count <= chars.Length);
-            Debug.Assert(offset + count <= chars.Length);
-
-            // ITU-T X.690 (08/2015) 8.23.5 says to encode IA5String as ISO/IEC 2022 using an implicit
-            // context of G0=6 (ANSI/ASCII) and no explicit escape sequences are allowed.
-            //
-            // That's a long-winded way of saying that it's just ASCII 0x00-0x7F.
-            byte[] encodedString = new byte[count];
-
-            for (int i = 0; i < count; i++)
-            {
-                char c = chars[i + offset];
-
-                // IA5 is ASCII 0x00-0x7F.
-                if (c > 127)
-                {
-                    throw new CryptographicException(SR.Cryptography_Invalid_IA5String);
-                }
-
-                encodedString[i] = (byte)c;
-            }
-
-            return new byte[][]
-            {
-                new byte[] { (byte)DerSequenceReader.DerTag.IA5String },
-                EncodeLength(encodedString.Length),
-                encodedString,
-            };
-        }
-
-        internal static byte[][] SegmentedEncodeUtcTime(DateTime utcTime)
-        {
-            Debug.Assert(utcTime.Kind == DateTimeKind.Utc);
-
-            // Low-allocating encoding of YYMMDDHHmmssZ
-            byte[] asciiDateBytes = new byte[13];
-
-            int year = utcTime.Year;
-            int month = utcTime.Month;
-            int day = utcTime.Day;
-            int hour = utcTime.Hour;
-            int minute = utcTime.Minute;
-            int second = utcTime.Second;
-
-            const byte Char0 = (byte)'0';
-
-            asciiDateBytes[1] = (byte)(Char0 + (year % 10));
-            year /= 10;
-            asciiDateBytes[0] = (byte)(Char0 + (year % 10));
-
-            asciiDateBytes[3] = (byte)(Char0 + (month % 10));
-            month /= 10;
-            asciiDateBytes[2] = (byte)(Char0 + (month % 10));
-
-            asciiDateBytes[5] = (byte)(Char0 + (day % 10));
-            day /= 10;
-            asciiDateBytes[4] = (byte)(Char0 + (day % 10));
-
-            asciiDateBytes[7] = (byte)(Char0 + (hour % 10));
-            hour /= 10;
-            asciiDateBytes[6] = (byte)(Char0 + (hour % 10));
-
-            asciiDateBytes[9] = (byte)(Char0 + (minute % 10));
-            minute /= 10;
-            asciiDateBytes[8] = (byte)(Char0 + (minute % 10));
-
-            asciiDateBytes[11] = (byte)(Char0 + (second % 10));
-            second /= 10;
-            asciiDateBytes[10] = (byte)(Char0 + (second % 10));
-
-            asciiDateBytes[12] = (byte)'Z';
-
-            return new[]
-            {
-                new byte[] { (byte)DerSequenceReader.DerTag.UTCTime },
-                EncodeLength(asciiDateBytes.Length),
-                asciiDateBytes,
-            };
-        }
-
-        internal static byte[][] SegmentedEncodeGeneralizedTime(DateTime utcTime)
-        {
-            Debug.Assert(utcTime.Kind == DateTimeKind.Utc);
-
-            // Low-allocating encoding of YYYYMMDDHHmmssZ
-            byte[] asciiDateBytes = new byte[15];
-
-            int year = utcTime.Year;
-            int month = utcTime.Month;
-            int day = utcTime.Day;
-            int hour = utcTime.Hour;
-            int minute = utcTime.Minute;
-            int second = utcTime.Second;
-
-            const byte Char0 = (byte)'0';
-
-            asciiDateBytes[3] = (byte)(Char0 + (year % 10));
-            year /= 10;
-            asciiDateBytes[2] = (byte)(Char0 + (year % 10));
-            year /= 10;
-            asciiDateBytes[1] = (byte)(Char0 + (year % 10));
-            year /= 10;
-            asciiDateBytes[0] = (byte)(Char0 + (year % 10));
-
-            asciiDateBytes[5] = (byte)(Char0 + (month % 10));
-            month /= 10;
-            asciiDateBytes[4] = (byte)(Char0 + (month % 10));
-
-            asciiDateBytes[7] = (byte)(Char0 + (day % 10));
-            day /= 10;
-            asciiDateBytes[6] = (byte)(Char0 + (day % 10));
-
-            asciiDateBytes[9] = (byte)(Char0 + (hour % 10));
-            hour /= 10;
-            asciiDateBytes[8] = (byte)(Char0 + (hour % 10));
-
-            asciiDateBytes[11] = (byte)(Char0 + (minute % 10));
-            minute /= 10;
-            asciiDateBytes[10] = (byte)(Char0 + (minute % 10));
-
-            asciiDateBytes[13] = (byte)(Char0 + (second % 10));
-            second /= 10;
-            asciiDateBytes[12] = (byte)(Char0 + (second % 10));
-
-            asciiDateBytes[14] = (byte)'Z';
-
-            return new[]
-            {
-                new byte[] { (byte)DerSequenceReader.DerTag.GeneralizedTime },
-                EncodeLength(asciiDateBytes.Length),
-                asciiDateBytes,
-            };
-        }
-
-        /// <summary>
-        /// Make a constructed SEQUENCE of the byte-triplets of the contents.
-        /// Each byte[][] should be a byte[][3] of {tag (1 byte), length (1-5 bytes), payload (variable)}.
-        /// </summary>
-        internal static byte[] ConstructSequence(params byte[][][] items)
-        {
-            return ConstructSequence((IEnumerable<byte[][]>)items);
-        }
-
-        /// <summary>
-        /// Make a constructed SEQUENCE of the byte-triplets of the contents.
-        /// Each byte[][] should be a byte[][3] of {tag (1 byte), length (1-5 bytes), payload (variable)}.
-        /// </summary>
-        internal static byte[] ConstructSequence(IEnumerable<byte[][]> items)
-        {
-            // A more robust solution would be required for public API.  DerInteger(int), DerBoolean, etc,
-            // which do not allow the user to specify lengths, but only the payload.  But for efficiency things
-            // are tracked as just little segments of bytes, and they're not glued together until this method.
-
-            int payloadLength = 0;
-
-            foreach (byte[][] segments in items)
-            {
-                foreach (byte[] segment in segments)
-                {
-                    payloadLength += segment.Length;
-                }
-            }
-
-            byte[] encodedLength = EncodeLength(payloadLength);
-            
-            // The tag (1) + the length of the length + the length of the payload
-            byte[] encodedSequence = new byte[1 + encodedLength.Length + payloadLength];
-
-            encodedSequence[0] = ConstructedSequenceTag;
-
-            int writeStart = 1;
-
-            Buffer.BlockCopy(encodedLength, 0, encodedSequence, writeStart, encodedLength.Length);
-
-            writeStart += encodedLength.Length;
-
-            foreach (byte[][] segments in items)
-            {
-                Debug.Assert(segments != null);
-                Debug.Assert(segments.Length == 3);
-
-                foreach (byte[] segment in segments)
-                {
-                    Debug.Assert(segment != null);
-
-                    Buffer.BlockCopy(segment, 0, encodedSequence, writeStart, segment.Length);
-                    writeStart += segment.Length;
-                }
-            }
-
-            return encodedSequence;
-        }
-
-        private static BigInteger ParseOidRid(string oidValue, ref int startIndex)
-        {
-            Debug.Assert(startIndex < oidValue.Length);
-
-            int endIndex = oidValue.IndexOf('.', startIndex);
-            
-            if (endIndex == -1)
-            {
-                endIndex = oidValue.Length;
-            }
-
-            Debug.Assert(endIndex > startIndex);
-
-            // The following code is equivalent to
-            // BigInteger.TryParse(temp, NumberStyles.None, CultureInfo.InvariantCulture, out value)
-            // but doesn't require creating the intermediate substring (TryParse doesn't take start+end/length values)
-
-            BigInteger value = BigInteger.Zero;
-
-            for (int position = startIndex; position < endIndex; position++)
-            {
-                value *= 10;
-                value += AtoI(oidValue[position]);
-            }
-
-            startIndex = endIndex + 1;
-            return value;
-        }
-
-        private static int AtoI(char c)
-        {
-            if (c >= '0' && c <= '9')
-                return c - '0';
-
-            throw new CryptographicException(SR.Argument_InvalidOidValue);
-        }
-
-        private static void EncodeRid(List<byte> encodedData, ref BigInteger rid)
-        {
-            BigInteger divisor = new BigInteger(128);
-            BigInteger unencoded = rid;
-
-            // The encoding is 7 bits of value and the 8th bit signifies "keep reading".
-            // So, for the input 1079 (0b0000 0100 0011 0111) the partitioning is
-            // 00|00 0100 0|011 0111, and the leading two bits are ignored.
-            // Therefore the encoded is 0b1000 1000 0011 0111 = 0x8837
-
-            Stack<byte> littleEndianBytes = new Stack<byte>();
-            byte continuance = 0;
-
-            do
-            {
-                BigInteger remainder;
-                unencoded = BigInteger.DivRem(unencoded, divisor, out remainder);
-
-                byte octet = (byte)remainder;
-                octet |= continuance;
-
-                // Any remaining (preceding) bytes need the continuance bit set.
-                continuance = 0x80;
-                littleEndianBytes.Push(octet);
-            }
-            while (unencoded != BigInteger.Zero);
-
-            encodedData.AddRange(littleEndianBytes);
-        }
-
-        private static bool IsPrintableStringCharacter(char c)
-        {
-            // ITU-T X.680 (11/2008)
-            // 41.4 (PrintableString)
-
-            // Latin Capital, Latin Small, Digits
-            if ((c >= 'A' && c <= 'Z') ||
-                (c >= 'a' && c <= 'z') ||
-                (c >= '0' && c <= '9'))
-            {
-                return true;
-            }
-
-            // Individually included characters
-            switch (c)
-            {
-                case ' ':
-                case '\'':
-                case '(':
-                case ')':
-                case '+':
-                case ',':
-                case '-':
-                case '.':
-                case '/':
-                case ':':
-                case '=':
-                case '?':
-                    return true;
-            }
-
-            return false;
-        }
-
-        private static byte[] ConcatenateArrays(params byte[][][] segments)
-        {
-            return ConcatenateArrays((IEnumerable<byte[][]>)segments);
-        }
-
-        private static byte[] ConcatenateArrays(IEnumerable<byte[][]> segments)
-        {
-            int length = 0;
-
-            foreach (byte[][] middleSegments in segments)
-            {
-                foreach (byte[] segment in middleSegments)
-                {
-                    length += segment.Length;
-                }
-            }
-
-            byte[] concatenated = new byte[length];
-
-            int offset = 0;
-
-            foreach (byte[][] middleSegments in segments)
-            {
-                foreach (byte[] segment in middleSegments)
-                {
-                    Buffer.BlockCopy(segment, 0, concatenated, offset, segment.Length);
-                    offset += segment.Length;
-                }
-            }
-
-            return concatenated;
-        }
-
-        private class AsnSetValueComparer : IComparer<byte[][]>, IComparer
-        {
-            public static AsnSetValueComparer Instance { get; } = new AsnSetValueComparer();
-
-            public int Compare(byte[][] x, byte[][] y)
-            {
-                Debug.Assert(x != null && y != null, "Comparing one more more null values");
-                Debug.Assert(x.Length == 3, $"x.Length is {x.Length} when it should be 3");
-                Debug.Assert(y.Length == 3, $"y.Length is {y.Length} when it should be 3");
-
-                // ITU-T X.690 11.6 Set-of components (CER/DER)
-                // The encodings of the component values of a set-of value shall appear in
-                // ascending order, the encodings being compared as octet strings with the
-                // shorter components being padded at their trailing end with 0-octets.
-                //
-                // ITU-T X.690 10.3 Set components (DER)
-                // The encodings of the component values of a set value shall appear in an
-                // order determined by their tags as specified in 8.6 of
-                // Rec. ITU-T X.680 | ISO/IEC 8824-1.
-                //
-                // ITU-T X.680 8.6
-                // The canonical order for tags is based on the outermost tag of each type
-                // and is defined as follows:
-                // a) those elements or alternatives with universal class tags shall appear
-                //    first, followed by those with application class tags, followed by those
-                //    with context-specific tags, followed by those with private class tags;
-                // b) within each class of tags, the elements or alternatives shall appear
-                //    in ascending order of their tag numbers.
-                //
-                // ITU-T X.690 8.1.2.2 says:
-                //   Universal:        0b00xxxxxx
-                //   Application:      0b01xxxxxx
-                //   Context-Specific: 0b10xxxxxx
-                //   Private:          0b11xxxxxx
-                //
-                // The net result is that the DER order is just lexicographic ordering by
-                // the TLV (tag-length-value) encoding. The comment in 11.6 about treating
-                // a shorter value as if it was right-padded with zeroes doesn't apply to DER,
-                // due to the length encoding. But for indefinite-length CER it would.
-                Debug.Assert(x[0].Length == 1, $"x[0].Length is {x[0].Length} when it should be 1");
-                Debug.Assert(y[0].Length == 1, $"y[0].Length is {y[0].Length} when it should be 1");
-
-                int comparison = x[0][0] - y[0][0];
-
-                if (comparison != 0)
-                    return comparison;
-
-                // The length encoding will always sort lexicographically based on its value, due to the
-                // length-or-length-length first byte. So skip over the [1] values and compare [2].Length.
-                comparison = x[2].Length - y[2].Length;
-
-                if (comparison != 0)
-                    return comparison;
-
-                for (int i = 0; i < x[2].Length; i++)
-                {
-                    comparison = x[2][i] - y[2][i];
-
-                    if (comparison != 0)
-                    {
-                        return comparison;
-                    }
-                }
-
-                return 0;
-            }
-
-            public int Compare(object x, object y)
-            {
-                return Compare(x as byte[][], y as byte[][]);
-            }
-        }
-    }
-}
diff --git a/src/libraries/Common/src/System/Security/Cryptography/DerSequenceReader.cs b/src/libraries/Common/src/System/Security/Cryptography/DerSequenceReader.cs
deleted file mode 100644 (file)
index 68d9ac1..0000000
+++ /dev/null
@@ -1,669 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Diagnostics;
-using System.Globalization;
-using System.Numerics;
-using System.Text;
-using System.Threading;
-
-namespace System.Security.Cryptography
-{
-    /// <summary>
-    /// Reads data encoded via the Distinguished Encoding Rules for Abstract
-    /// Syntax Notation 1 (ASN.1) data.
-    /// </summary>
-    internal class DerSequenceReader
-    {
-        internal const byte ContextSpecificTagFlag = 0x80;
-        internal const byte ConstructedFlag = 0x20;
-        internal const byte ContextSpecificConstructedTag0 = ContextSpecificTagFlag | ConstructedFlag;
-        internal const byte ContextSpecificConstructedTag1 = ContextSpecificConstructedTag0 | 1;
-        internal const byte ContextSpecificConstructedTag2 = ContextSpecificConstructedTag0 | 2;
-        internal const byte ContextSpecificConstructedTag3 = ContextSpecificConstructedTag0 | 3;
-        internal const byte ConstructedSequence = ConstructedFlag | (byte)DerTag.Sequence;
-
-        // 0b1100_0000
-        internal const byte TagClassMask = 0xC0; 
-        internal const byte TagNumberMask = 0x1F;
-
-        internal static DateTimeFormatInfo s_validityDateTimeFormatInfo;
-
-        private static System.Text.Encoding s_utf8EncodingWithExceptionFallback;
-        private static System.Text.Encoding s_latin1Encoding;
-
-        private readonly byte[] _data;
-        private readonly int _end;
-        private int _position;
-
-        internal int ContentLength { get; private set; }
-
-        private DerSequenceReader(bool startAtPayload, byte[] data, int offset, int length)
-        {
-            Debug.Assert(startAtPayload, "This overload is only for bypassing the sequence tag");
-            Debug.Assert(data != null, "Data is null");
-            Debug.Assert(offset >= 0, "Offset is negative");
-
-            _data = data;
-            _position = offset;
-            _end = offset + length;
-
-            ContentLength = length;
-        }
-
-        internal DerSequenceReader(byte[] data)
-            : this(data, 0, data.Length)
-        {
-        }
-
-        internal DerSequenceReader(byte[] data, int offset, int length)
-            : this(DerTag.Sequence, data, offset, length)
-        {
-        }
-
-        private DerSequenceReader(DerTag tagToEat, byte[] data, int offset, int length)
-        {
-            Debug.Assert(data != null, "Data is null");
-
-            if (offset < 0 || length < 2 || length > data.Length - offset)
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-            _data = data;
-            _end = offset + length;
-            _position = offset;
-            EatTag(tagToEat);
-            int contentLength = EatLength();
-            Debug.Assert(_end - contentLength >= _position);
-            ContentLength = contentLength;
-
-            // If the sequence reports being smaller than the buffer, shrink the end-of-validity.
-            _end = _position + contentLength;
-        }
-
-        internal static DerSequenceReader CreateForPayload(byte[] payload)
-        {
-            return new DerSequenceReader(true, payload, 0, payload.Length);
-        }
-
-        internal bool HasData
-        {
-            get { return _position < _end; }
-        }
-
-        internal byte PeekTag()
-        {
-            if (!HasData)
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-            byte tag = _data[_position];
-
-            if ((tag & TagNumberMask) == TagNumberMask)
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            return tag;
-        }
-
-        internal bool HasTag(DerTag expectedTag)
-        {
-            return HasTag((byte)expectedTag);
-        }
-
-        internal bool HasTag(byte expectedTag)
-        {
-            return HasData && _data[_position] == expectedTag;
-        }
-
-        internal void SkipValue()
-        {
-            EatTag((DerTag)PeekTag());
-            int contentLength = EatLength();
-            _position += contentLength;
-        }
-
-        internal void ValidateAndSkipDerValue()
-        {
-            byte tag = PeekTag();
-
-            // If the tag is in the UNIVERSAL class
-            if ((tag & TagClassMask) == 0)
-            {
-                // Tag 0 is special ("reserved for use by the encoding rules"), but mainly is used
-                // as the End-of-Contents marker for the indefinite length encodings, which DER prohibits.
-                //
-                // Tag 15 is reserved.
-                //
-                // So either of these are invalid.
-
-                if (tag == 0 || tag == 15)
-                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-                // DER limits the constructed encoding to SEQUENCE and SET, as well as anything which gets
-                // a defined encoding as being an IMPLICIT SEQUENCE.
-
-                bool expectConstructed = false;
-
-                switch (tag & TagNumberMask)
-                {
-                    case 0x08: // External or Instance-Of
-                    case 0x0B: // EmbeddedPDV
-                    case (byte)DerTag.Sequence:
-                    case (byte)DerTag.Set:
-                    case 0x1D: // Unrestricted Character String
-                        expectConstructed = true;
-                        break;
-                }
-
-                bool isConstructed = (tag & ConstructedFlag) == ConstructedFlag;
-
-                if (expectConstructed != isConstructed)
-                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            EatTag((DerTag)tag);
-            int contentLength = EatLength();
-
-            if (contentLength > 0 && (tag & ConstructedFlag) == ConstructedFlag)
-            {
-                var childReader = new DerSequenceReader(true, _data, _position, _end - _position);
-
-                while (childReader.HasData)
-                {
-                    childReader.ValidateAndSkipDerValue();
-                }
-            }
-
-            _position += contentLength;
-        }
-
-        /// <summary>
-        /// Returns the next value encoded (this includes tag and length)
-        /// </summary>
-        internal byte[] ReadNextEncodedValue()
-        {
-            // Check that the tag is legal, but the value isn't relevant.
-            PeekTag();
-
-            int lengthLength;
-            int contentLength = ScanContentLength(_data, _position + 1, _end, out lengthLength);
-            // Length of tag, encoded length, and the content
-            int totalLength = 1 + lengthLength + contentLength;
-            Debug.Assert(_end - totalLength >= _position);
-            
-            byte[] encodedValue = new byte[totalLength];
-            Buffer.BlockCopy(_data, _position, encodedValue, 0, totalLength);
-
-            _position += totalLength;
-            return encodedValue;
-        }
-
-        internal bool ReadBoolean()
-        {
-            EatTag(DerTag.Boolean);
-
-            int length = EatLength();
-
-            if (length != 1)
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-            bool value = _data[_position] != 0;
-            _position += length;
-            return value;
-        }
-
-        internal int ReadInteger()
-        {
-            byte[] integerBytes = ReadIntegerBytes();
-
-            // integerBytes is currently Big-Endian, need to reverse it for
-            // Little-Endian to pass into BigInteger.
-            Array.Reverse(integerBytes);
-            BigInteger bigInt = new BigInteger(integerBytes);
-            return (int)bigInt;
-        }
-
-        internal byte[] ReadIntegerBytes()
-        {
-            EatTag(DerTag.Integer);
-
-            return ReadContentAsBytes();
-        }
-
-        internal byte[] ReadBitString()
-        {
-            EatTag(DerTag.BitString);
-
-            int contentLength = EatLength();
-
-            if (contentLength < 1)
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-            byte unusedBits = _data[_position];
-
-            if (unusedBits > 7)
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-            // skip the "unused bits" byte
-            contentLength--;
-            _position++;
-
-            byte[] octets = new byte[contentLength];
-            Buffer.BlockCopy(_data, _position, octets, 0, contentLength);
-
-            _position += contentLength;
-            return octets;
-        }
-
-        internal byte[] ReadOctetString()
-        {
-            EatTag(DerTag.OctetString);
-
-            return ReadContentAsBytes();
-        }
-
-        internal string ReadOidAsString()
-        {
-            EatTag(DerTag.ObjectIdentifier);
-            int contentLength = EatLength();
-
-            if (contentLength < 1)
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-            // Each byte could cause 3 decimal characters to be written, plus a period. Over-allocate
-            // and avoid re-alloc.
-            StringBuilder builder = new StringBuilder(contentLength * 4);
-
-            // The first byte is ((X * 40) + Y), where X is the first segment and Y the second.
-            // ISO/IEC 8825-1:2003 section 8.19.4
-
-            byte firstByte = _data[_position];
-            byte first = (byte)(firstByte / 40);
-            byte second = (byte)(firstByte % 40);
-
-            builder.Append(first);
-            builder.Append('.');
-            builder.Append(second);
-
-            // For the rest of the segments, the high bit on the byte is a continuation marker,
-            // and data is loaded into a BigInteger 7 bits at a time.
-            //
-            // When the high bit is 0, the segment ends, so emit a '.' between it and the next one.
-            //
-            // ISO/IEC 8825-1:2003 section 8.19.2, and the .NET representation of Oid.Value.
-            bool needDot = true;
-            BigInteger bigInt = new BigInteger(0);
-
-            for (int i = 1; i < contentLength; i++)
-            {
-                byte current = _data[_position + i];
-                byte data = (byte)(current & 0x7F);
-
-                if (needDot)
-                {
-                    builder.Append('.');
-                    needDot = false;
-                }
-
-                bigInt <<= 7;
-                bigInt += data;
-
-                if (current == data)
-                {
-                    builder.Append(bigInt);
-                    bigInt = 0;
-                    needDot = true;
-                }
-            }
-
-            _position += contentLength;
-            return builder.ToString();
-        }
-
-        internal Oid ReadOid()
-        {
-            return new Oid(ReadOidAsString());
-        }
-
-        internal string ReadUtf8String()
-        {
-            EatTag(DerTag.UTF8String);
-            int contentLength = EatLength();
-
-            string str = System.Text.Encoding.UTF8.GetString(_data, _position, contentLength);
-            _position += contentLength;
-
-            return TrimTrailingNulls(str);
-        }
-
-        private DerSequenceReader ReadCollectionWithTag(DerTag expected)
-        {
-            // DerSequenceReader wants to read its own tag, so don't EatTag here.
-            CheckTag(expected, _data, _position);
-
-            int lengthLength;
-            int contentLength = ScanContentLength(_data, _position + 1, _end, out lengthLength);
-            int totalLength = 1 + lengthLength + contentLength;
-
-            DerSequenceReader reader = new DerSequenceReader(expected, _data, _position, totalLength);
-            _position += totalLength;
-            return reader;
-        }
-
-        internal DerSequenceReader ReadSequence()
-        {
-            return ReadCollectionWithTag(DerTag.Sequence);
-        }
-
-        internal DerSequenceReader ReadSet()
-        {
-            return ReadCollectionWithTag(DerTag.Set);
-        }
-
-        internal string ReadPrintableString()
-        {
-            EatTag(DerTag.PrintableString);
-            int contentLength = EatLength();
-
-            // PrintableString is a subset of ASCII, so just return the ASCII interpretation.
-            string str = System.Text.Encoding.ASCII.GetString(_data, _position, contentLength);
-            _position += contentLength;
-
-            return TrimTrailingNulls(str);
-        }
-
-        internal string ReadIA5String()
-        {
-            EatTag(DerTag.IA5String);
-            int contentLength = EatLength();
-
-            // IA5 (International Alphabet - 5) is functionally equivalent to 7-bit ASCII.
-
-            string ia5String = System.Text.Encoding.ASCII.GetString(_data, _position, contentLength);
-            _position += contentLength;
-
-            return TrimTrailingNulls(ia5String);
-        }
-
-        internal string ReadT61String()
-        {
-            EatTag(DerTag.T61String);
-            int contentLength = EatLength();
-            string t61String;
-
-            // Technically the T.61 encoding (code page 20261) should be used here, but many
-            // implementations don't follow that and use different character sets. CryptoAPI
-            // on NetFX seems to interpret it as UTF-8 with fallback to ISO 8859-1. OpenSSL
-            // seems to interpret it as ISO 8859-1 with no support for UTF-8.
-            // https://github.com/dotnet/corefx/issues/27466
-
-            System.Text.Encoding utf8EncodingWithExceptionFallback = LazyInitializer.EnsureInitialized(
-                ref s_utf8EncodingWithExceptionFallback,
-                () => new UTF8Encoding(false, true));
-            System.Text.Encoding latin1Encoding = LazyInitializer.EnsureInitialized(
-                ref s_latin1Encoding,
-                () => System.Text.Encoding.GetEncoding("iso-8859-1"));
-            
-            try
-            {
-                t61String = utf8EncodingWithExceptionFallback.GetString(_data, _position, contentLength);
-            }
-            catch (DecoderFallbackException)
-            {
-                t61String = latin1Encoding.GetString(_data, _position, contentLength);
-            }
-            _position += contentLength;
-
-            return TrimTrailingNulls(t61String);
-        }
-
-        internal DateTime ReadX509Date()
-        {
-            byte tag = PeekTag();
-
-            switch ((DerTag)tag)
-            {
-                case DerTag.UTCTime:
-                    return ReadUtcTime();
-                case DerTag.GeneralizedTime:
-                    return ReadGeneralizedTime();
-            }
-
-            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-        }
-
-        internal DateTime ReadUtcTime()
-        {
-            return ReadTime(DerTag.UTCTime, "yyMMddHHmmss'Z'");
-        }
-
-        internal DateTime ReadGeneralizedTime()
-        {
-            // Currently only supports reading times with no fractional seconds or time differentials
-            // as RFC 2630 doesn't allow these. In case this is done, the format string has to be parsed
-            // to follow rules on X.680 and X.690.
-            return ReadTime(DerTag.GeneralizedTime, "yyyyMMddHHmmss'Z'");
-        }
-
-        internal string ReadBMPString()
-        {
-            EatTag(DerTag.BMPString);
-            int contentLength = EatLength();
-
-            // BMPString or Basic Multilingual Plane, is equal to UCS-2.
-            // And since this is cryptography, it's Big Endian.
-            string str = System.Text.Encoding.BigEndianUnicode.GetString(_data, _position, contentLength);
-            _position += contentLength;
-
-            return TrimTrailingNulls(str);
-        }
-
-        private static string TrimTrailingNulls(string value)
-        {
-            // .NET's string comparisons start by checking the length, so a trailing
-            // NULL character which was literally embedded in the DER would cause a
-            // failure in .NET whereas it wouldn't have with strcmp.
-            if (value?.Length > 0)
-            {
-                int newLength = value.Length;
-
-                while (newLength > 0 && value[newLength - 1] == 0)
-                {
-                    newLength--;
-                }
-
-                if (newLength != value.Length)
-                {
-                    return value.Substring(0, newLength);
-                }
-            }
-
-            return value;
-        }
-
-        private DateTime ReadTime(DerTag timeTag, string formatString)
-        {
-            EatTag(timeTag);
-            int contentLength = EatLength();
-
-            string decodedTime = System.Text.Encoding.ASCII.GetString(_data, _position, contentLength);
-            _position += contentLength;
-
-            Debug.Assert(
-                decodedTime[decodedTime.Length - 1] == 'Z',
-                $"The date doesn't follow the X.690 format, ending with {decodedTime[decodedTime.Length - 1]}");
-
-            DateTime time;
-
-            DateTimeFormatInfo fi = LazyInitializer.EnsureInitialized(
-                ref s_validityDateTimeFormatInfo,
-                () =>
-                {
-                    var clone = (DateTimeFormatInfo)CultureInfo.InvariantCulture.DateTimeFormat.Clone();
-                    clone.Calendar.TwoDigitYearMax = 2049;
-
-                    return clone;
-                });
-
-            if (!DateTime.TryParseExact(
-                    decodedTime,
-                    formatString,
-                    fi,
-                    DateTimeStyles.AssumeUniversal | DateTimeStyles.AdjustToUniversal,
-                    out time))
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            return time;
-        }
-
-        private byte[] ReadContentAsBytes()
-        {
-            int contentLength = EatLength();
-
-            byte[] octets = new byte[contentLength];
-            Buffer.BlockCopy(_data, _position, octets, 0, contentLength);
-
-            _position += contentLength;
-            return octets;
-        }
-
-        private void EatTag(DerTag expected)
-        {
-            if (!HasData)
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-            CheckTag(expected, _data, _position);
-            _position++;
-        }
-
-        private static void CheckTag(DerTag expected, byte[] data, int position)
-        {
-            if (position >= data.Length)
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-            byte actual = data[position];
-            byte relevant = (byte)(actual & TagNumberMask);
-
-            // Multi-byte tags are not supported by this implementation.
-            if (relevant == TagNumberMask)
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            // Context-specific datatypes cannot be tag-verified
-            if ((actual & ContextSpecificTagFlag) != 0)
-            {
-                return;
-            }
-
-            byte expectedByte = (byte)((byte)expected & TagNumberMask);
-
-            if (expectedByte != relevant)
-            {
-                throw new CryptographicException(
-                    SR.Cryptography_Der_Invalid_Encoding
-#if DEBUG
-                    ,
-                    new InvalidOperationException(
-                        "Expected tag '0x" + expectedByte.ToString("X2") +
-                            "', got '0x" + actual.ToString("X2") +
-                            "' at position " + position)
-#endif
-                    );
-            }
-        }
-
-        private int EatLength()
-        {
-            int bytesConsumed;
-            int answer = ScanContentLength(_data, _position, _end, out bytesConsumed);
-
-            _position += bytesConsumed;
-            return answer;
-        }
-
-        private static int ScanContentLength(byte[] data, int offset, int end, out int bytesConsumed)
-        {
-            Debug.Assert(end <= data.Length);
-
-            if (offset >= end)
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-            byte lengthOrLengthLength = data[offset];
-
-            if (lengthOrLengthLength < 0x80)
-            {
-                bytesConsumed = 1;
-
-                if (lengthOrLengthLength > end - offset - bytesConsumed)
-                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-                return lengthOrLengthLength;
-            }
-
-            int lengthLength = (lengthOrLengthLength & 0x7F);
-
-            if (lengthLength > sizeof(int))
-            {
-                // .NET Arrays cannot exceed int.MaxValue in length. Since we're bounded by an
-                // array we know that this is invalid data.
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            // The one byte which was lengthLength, plus the number of bytes it said to consume.
-            bytesConsumed = 1 + lengthLength;
-
-            if (bytesConsumed > end - offset)
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-            // CER indefinite length is not supported.
-            if (bytesConsumed == 1)
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-            int lengthEnd = offset + bytesConsumed;
-            int accum = 0;
-            
-            // data[offset] is lengthLength, so start at data[offset + 1] and stop before
-            // data[offset + 1 + lengthLength], aka data[end].
-            for (int i = offset + 1; i < lengthEnd; i++)
-            {
-                accum <<= 8;
-                accum |= data[i];
-            }
-
-            if (accum < 0)
-            {
-                // .NET Arrays cannot exceed int.MaxValue in length. Since we're bounded by an
-                // array we know that this is invalid data.
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            if (accum > end - offset - bytesConsumed)
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-
-            return accum;
-        }
-
-        internal enum DerTag : byte
-        {
-            Boolean = 0x01,
-            Integer = 0x02,
-            BitString = 0x03,
-            OctetString = 0x04,
-            Null = 0x05,
-            ObjectIdentifier = 0x06,
-            UTF8String = 0x0C,
-            Sequence = 0x10,
-            Set = 0x11,
-            PrintableString = 0x13,
-            T61String = 0x14,
-            IA5String = 0x16,
-            UTCTime = 0x17,
-            GeneralizedTime = 0x18,
-            BMPString = 0x1E,
-        }
-    }
-}
diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/DerEncoderTests.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/DerEncoderTests.cs
deleted file mode 100644 (file)
index 5ea5a19..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Text;
-using Test.Cryptography;
-using Xunit;
-
-namespace System.Security.Cryptography.Encoding.Tests
-{
-    public class DerEncoderTests
-    {
-        [Theory]
-        [InlineData("00", 0x02, "01", "00")]
-        [InlineData("01", 0x02, "01", "01")]
-        [InlineData("7F", 0x02, "01", "7F")]
-        [InlineData("80", 0x02, "02", "0080")]
-        [InlineData("FF", 0x02, "02", "00FF")]
-        [InlineData("00FF", 0x02, "02", "00FF")]
-        [InlineData("01FF", 0x02, "02", "01FF")]
-        [InlineData("7FFF", 0x02, "02", "7FFF")]
-        [InlineData("8000", 0x02, "03", "008000")]
-        [InlineData("FFFF", 0x02, "03", "00FFFF")]
-        [InlineData("00FFFF", 0x02, "03", "00FFFF")]
-        [InlineData("7FFFFF", 0x02, "03", "7FFFFF")]
-        [InlineData("800000", 0x02, "04", "00800000")]
-        [InlineData("FFFFFF", 0x02, "04", "00FFFFFF")]
-        [InlineData("00FFFFFF", 0x02, "04", "00FFFFFF")]
-        [InlineData("7FFFFFFF", 0x02, "04", "7FFFFFFF")]
-        [InlineData("80000000", 0x02, "05", "0080000000")]
-        [InlineData("FFFFFFFF", 0x02, "05", "00FFFFFFFF")]
-        [InlineData("0123456789ABCDEF", 0x02, "08", "0123456789ABCDEF")]
-        [InlineData("FEDCBA9876543210", 0x02, "09", "00FEDCBA9876543210")]
-        public static void ValidateUintEncodings(string hexRaw, byte tag, string hexLength, string hexValue)
-        {
-            byte[] raw = hexRaw.HexToByteArray();
-            byte[] length = hexLength.HexToByteArray();
-            byte[] value = hexValue.HexToByteArray();
-
-            byte[][] segments = DerEncoder.SegmentedEncodeUnsignedInteger(raw);
-
-            Assert.Equal(3, segments.Length);
-
-            Assert.Equal(new[] { tag }, segments[0]);
-            Assert.Equal(length, segments[1]);
-            Assert.Equal(value, segments[2]);
-        }
-
-        [Theory]
-        [InlineData("", 0, "01", "00")]
-        [InlineData("00", 0, "02", "0000")]
-        [InlineData("00", 7, "02", "0700")]
-        [InlineData("0000", 0, "03", "000000")]
-        [InlineData("007F", 7, "03", "070000")]
-        [InlineData("007F", 6, "03", "060040")]
-        [InlineData("007F", 5, "03", "050060")]
-        [InlineData("007F", 4, "03", "040070")]
-        [InlineData("007F", 3, "03", "030078")]
-        [InlineData("007F", 2, "03", "02007C")]
-        [InlineData("007F", 1, "03", "01007E")]
-        [InlineData("007F", 0, "03", "00007F")]
-        public static void ValidateBitStringEncodings(string hexRaw, int unusedBits, string hexLength, string encodedData)
-        {
-            byte[] input = hexRaw.HexToByteArray();
-            const byte tag = 0x03;
-            byte[] length = hexLength.HexToByteArray();
-            byte[] expectedOutput = encodedData.HexToByteArray();
-
-            byte[][] segments = DerEncoder.SegmentedEncodeBitString(unusedBits, input);
-
-            Assert.Equal(3, segments.Length);
-
-            Assert.Equal(new[] { tag }, segments[0]);
-            Assert.Equal(length, segments[1]);
-            Assert.Equal(expectedOutput, segments[2]);
-        }
-
-        [Theory]
-        [InlineData("", 9, "01", "00")]
-        [InlineData("00", 9, "01", "00")]
-        [InlineData("0000", 9, "01", "00")]
-        [InlineData("007F", 9, "01", "00")]
-        [InlineData("8000", 3, "02", "0780")]
-        [InlineData("8FF0", 3, "02", "0780")]
-        [InlineData("8FF0", 7, "02", "018E")]
-        [InlineData("8FF0", 8, "02", "008F")]
-        [InlineData("8FF0", 9, "03", "078F80")]
-        public static void ValidateNamedBitEncodings(string hexRaw, int namedBits, string hexLength, string encodedData)
-        {
-            byte[] input = hexRaw.HexToByteArray();
-            const byte tag = 0x03;
-            byte[] length = hexLength.HexToByteArray();
-            byte[] expectedOutput = encodedData.HexToByteArray();
-
-            byte[][] segments = DerEncoder.SegmentedEncodeNamedBitList(input, namedBits);
-
-            Assert.Equal(3, segments.Length);
-            
-            Assert.Equal(new[] { tag }, segments[0]);
-            Assert.Equal(length, segments[1]);
-            Assert.Equal(expectedOutput, segments[2]);
-        }
-
-        [Theory]
-        [InlineData("010203040506070809", "09")]
-        [InlineData("", "00")]
-        public static void ValidateOctetStringEncodings(string hexData, string hexLength)
-        {
-            byte[] input = hexData.HexToByteArray();
-            const byte tag = 0x04;
-            byte[] length = hexLength.HexToByteArray();
-
-            byte[][] segments = DerEncoder.SegmentedEncodeOctetString(input);
-
-            Assert.Equal(3, segments.Length);
-
-            Assert.Equal(new[] { tag }, segments[0]);
-            Assert.Equal(length, segments[1]);
-            Assert.Equal(input, segments[2]);
-        }
-
-        [Theory]
-        [InlineData("1.3.6.1.5.5.7.3.1", "08", "2B06010505070301")]
-        [InlineData("1.3.6.1.5.5.7.3.2", "08", "2B06010505070302")]
-        [InlineData("1.3.132.0.34", "05", "2B81040022")]
-        [InlineData("2.999.3", "03", "883703")]
-        [InlineData("2.999.19427512891.25", "08", "8837C8AFE1A43B19")]
-        public static void ValidateOidEncodings(string oidValue, string hexLength, string encodedData)
-        {
-            Oid oid = new Oid(oidValue, oidValue);
-            const byte tag = 0x06;
-            byte[] length = hexLength.HexToByteArray();
-            byte[] expectedOutput = encodedData.HexToByteArray();
-
-            byte[][] segments = DerEncoder.SegmentedEncodeOid(oid);
-
-            Assert.Equal(3, segments.Length);
-
-            Assert.Equal(new[] { tag }, segments[0]);
-            Assert.Equal(length, segments[1]);
-            Assert.Equal(expectedOutput, segments[2]);
-        }
-
-        [Fact]
-        public static void ConstructSequence()
-        {
-            byte[] expected =
-            {
-                /* SEQUENCE */     0x30, 0x07,
-                /* INTEGER(0) */   0x02, 0x01, 0x00,
-                /* INTEGER(256) */ 0x02, 0x02, 0x01, 0x00,
-            };
-
-            byte[] encoded = DerEncoder.ConstructSequence(
-                DerEncoder.SegmentedEncodeUnsignedInteger(new byte[] { 0x00 }),
-                DerEncoder.SegmentedEncodeUnsignedInteger(new byte[] { 0x01, 0x00 }));
-
-            Assert.Equal(expected, encoded);
-        }
-
-        [Theory]
-        [InlineData("", true)]
-        [InlineData("This is a PrintableString.", true)]
-        [InlineData("This is not @ PrintableString.", false)]
-        [InlineData("\u65E5\u672C\u8A9E is not a PrintableString", false)]
-        public static void CheckPrintableString(string candidate, bool expected)
-        {
-            Assert.Equal(expected, DerEncoder.IsValidPrintableString(candidate.ToCharArray()));
-        }
-
-        // No bounds check tests are done here, because the method is currently assert-based,
-        // not exception-based.
-        [Theory]
-        [InlineData("", 0, 0, true)]
-        [InlineData("This is a PrintableString.", 0, 26, true)]
-        [InlineData("This is not @ PrintableString.", 0, 30, false)]
-        [InlineData("This is not @ PrintableString.", 0, 12, true)]
-        [InlineData("This is not @ PrintableString.", 12, 0, true)]
-        [InlineData("This is not @ PrintableString.", 12, 1, false)]
-        [InlineData("This is not @ PrintableString.", 13, 17, true)]
-        [InlineData("\u65E5\u672C\u8A9E is not a PrintableString", 0, 27, false)]
-        [InlineData("\u65E5\u672C\u8A9E is not a PrintableString", 0, 0, true)]
-        [InlineData("\u65E5\u672C\u8A9E is not a PrintableString", 3, 24, true)]
-        public static void CheckPrintableSubstring(string candidate, int offset, int length, bool expected)
-        {
-            Assert.Equal(expected, DerEncoder.IsValidPrintableString(candidate.ToCharArray(), offset, length));
-        }
-
-        [Theory]
-        [InlineData("", "")]
-        [InlineData("Hello", "48656C6C6F")]
-        [InlineData("banana", "62616E616E61")]
-        public static void CheckIA5StringEncoding(string input, string expectedHex)
-        {
-            byte[][] encodedString = DerEncoder.SegmentedEncodeIA5String(input.ToCharArray());
-
-            Assert.NotNull(encodedString);
-            Assert.Equal(3, encodedString.Length);
-
-            // Check the tag
-            Assert.NotNull(encodedString[0]);
-            Assert.Equal(1, encodedString[0].Length);
-            Assert.Equal(0x16, encodedString[0][0]);
-
-            // Check the length. Since the input cases are all less than 0x7F bytes
-            // the length is only one byte.
-            Assert.NotNull(encodedString[1]);
-            Assert.Equal(1, encodedString[1].Length);
-            Assert.Equal(expectedHex.Length / 2, encodedString[1][0]);
-
-            // Check the value
-            Assert.Equal(expectedHex.HexToByteArray(), encodedString[2]);
-
-            // And, full roundtrip
-            Assert.Equal(input, Text.Encoding.ASCII.GetString(encodedString[2]));
-        }
-
-        [Theory]
-        [InlineData("Hello", 3, 2, "6C6F")]
-        [InlineData("banana", 1, 4, "616E616E")]
-        public static void CheckIA5SubstringEncoding(string input, int offset, int length, string expectedHex)
-        {
-            byte[][] encodedString = DerEncoder.SegmentedEncodeIA5String(input.ToCharArray(), offset, length);
-
-            Assert.NotNull(encodedString);
-            Assert.Equal(3, encodedString.Length);
-
-            // Check the tag
-            Assert.NotNull(encodedString[0]);
-            Assert.Equal(1, encodedString[0].Length);
-            Assert.Equal(0x16, encodedString[0][0]);
-
-            // Check the length. Since the input cases are all less than 0x7F bytes
-            // the length is only one byte.
-            Assert.NotNull(encodedString[1]);
-            Assert.Equal(1, encodedString[1].Length);
-            Assert.Equal(expectedHex.Length / 2, encodedString[1][0]);
-
-            // Check the value
-            Assert.Equal(expectedHex.HexToByteArray(), encodedString[2]);
-
-            // And, full roundtrip
-            Assert.Equal(input.Substring(offset, length), Text.Encoding.ASCII.GetString(encodedString[2]));
-        }
-
-        [Theory]
-        [InlineData("", "")]
-        [InlineData("Hello", "48656C6C6F")]
-        [InlineData("banana", "62616E616E61")]
-        public static void CheckPrintableStringEncoding(string input, string expectedHex)
-        {
-            byte[][] encodedString = DerEncoder.SegmentedEncodePrintableString(input.ToCharArray());
-
-            Assert.NotNull(encodedString);
-            Assert.Equal(3, encodedString.Length);
-
-            // Check the tag
-            Assert.NotNull(encodedString[0]);
-            Assert.Equal(1, encodedString[0].Length);
-            Assert.Equal(0x13, encodedString[0][0]);
-
-            // Check the length. Since the input cases are all less than 0x7F bytes
-            // the length is only one byte.
-            Assert.NotNull(encodedString[1]);
-            Assert.Equal(1, encodedString[1].Length);
-            Assert.Equal(expectedHex.Length / 2, encodedString[1][0]);
-
-            // Check the value
-            Assert.Equal(expectedHex.HexToByteArray(), encodedString[2]);
-
-            // And, full roundtrip
-            Assert.Equal(input, Text.Encoding.ASCII.GetString(encodedString[2]));
-        }
-
-        [Theory]
-        [InlineData("Hello", 3, 2, "6C6F")]
-        [InlineData("banana", 1, 4, "616E616E")]
-        public static void CheckPrintableSubstringEncoding(string input, int offset, int length, string expectedHex)
-        {
-            byte[][] encodedString = DerEncoder.SegmentedEncodePrintableString(input.ToCharArray(), offset, length);
-
-            Assert.NotNull(encodedString);
-            Assert.Equal(3, encodedString.Length);
-
-            // Check the tag
-            Assert.NotNull(encodedString[0]);
-            Assert.Equal(1, encodedString[0].Length);
-            Assert.Equal(0x13, encodedString[0][0]);
-
-            // Check the length. Since the input cases are all less than 0x7F bytes
-            // the length is only one byte.
-            Assert.NotNull(encodedString[1]);
-            Assert.Equal(1, encodedString[1].Length);
-            Assert.Equal(expectedHex.Length / 2, encodedString[1][0]);
-
-            // Check the value
-            Assert.Equal(expectedHex.HexToByteArray(), encodedString[2]);
-
-            // And, full roundtrip
-            Assert.Equal(input.Substring(offset, length), Text.Encoding.ASCII.GetString(encodedString[2]));
-        }
-
-        [Theory]
-        [InlineData("", "")]
-        [InlineData("Hello", "48656C6C6F")]
-        [InlineData("banana", "62616E616E61")]
-        [InlineData("\u65E5\u672C\u8A9E", "E697A5E69CACE8AA9E")]
-        public static void CheckUTF8StringEncoding(string input, string expectedHex)
-        {
-            byte[][] encodedString = DerEncoder.SegmentedEncodeUtf8String(input.ToCharArray());
-
-            Assert.NotNull(encodedString);
-            Assert.Equal(3, encodedString.Length);
-
-            // Check the tag
-            Assert.NotNull(encodedString[0]);
-            Assert.Equal(1, encodedString[0].Length);
-            Assert.Equal(0x0C, encodedString[0][0]);
-
-            // Check the length. Since the input cases are all less than 0x7F bytes
-            // the length is only one byte.
-            Assert.NotNull(encodedString[1]);
-            Assert.Equal(1, encodedString[1].Length);
-            Assert.Equal(expectedHex.Length / 2, encodedString[1][0]);
-
-            // Check the value
-            Assert.Equal(expectedHex.HexToByteArray(), encodedString[2]);
-
-            // And, full roundtrip
-            Assert.Equal(input, Text.Encoding.UTF8.GetString(encodedString[2]));
-        }
-
-        [Theory]
-        [InlineData("Hello", 3, 2, "6C6F")]
-        [InlineData("banana", 1, 4, "616E616E")]
-        [InlineData("\u65E5\u672C\u8A9E", 1, 1, "E69CAC")]
-        public static void CheckUTF8SubstringEncoding(string input, int offset, int length, string expectedHex)
-        {
-            byte[][] encodedString = DerEncoder.SegmentedEncodeUtf8String(input.ToCharArray(), offset, length);
-            Assert.NotNull(encodedString);
-            Assert.Equal(3, encodedString.Length);
-
-            // Check the tag
-            Assert.NotNull(encodedString[0]);
-            Assert.Equal(1, encodedString[0].Length);
-            Assert.Equal(0x0C, encodedString[0][0]);
-
-            // Check the length. Since the input cases are all less than 0x7F bytes
-            // the length is only one byte.
-            Assert.NotNull(encodedString[1]);
-            Assert.Equal(1, encodedString[1].Length);
-            Assert.Equal(expectedHex.Length / 2, encodedString[1][0]);
-
-            // Check the value
-            Assert.Equal(expectedHex.HexToByteArray(), encodedString[2]);
-
-            // And, full roundtrip
-            Assert.Equal(input.Substring(offset, length), Text.Encoding.UTF8.GetString(encodedString[2]));
-        }
-    }
-}
diff --git a/src/libraries/System.Security.Cryptography.Encoding/tests/DerSequenceReaderTests.cs b/src/libraries/System.Security.Cryptography.Encoding/tests/DerSequenceReaderTests.cs
deleted file mode 100644 (file)
index f63802b..0000000
+++ /dev/null
@@ -1,210 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-
-using System.Numerics;
-using Test.Cryptography;
-using Xunit;
-
-namespace System.Security.Cryptography.Encoding.Tests
-{
-    public class DerSequenceReaderTests
-    {
-        [Fact]
-        public static void ReadIntegers()
-        {
-            byte[] derEncoded =
-            {
-                /* SEQUENCE */     0x30, 23,
-                /* INTEGER(0) */   0x02, 0x01, 0x00,
-                /* INTEGER(256) */ 0x02, 0x02, 0x01, 0x00,
-                /* INTEGER(-1) */  0x02, 0x01, 0xFF,
-                /* Big integer */  0x02, 0x0B, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D,
-            };
-
-            DerSequenceReader reader = new DerSequenceReader(derEncoded);
-            Assert.True(reader.HasData);
-            Assert.Equal(23, reader.ContentLength);
-
-            int first = reader.ReadInteger();
-            Assert.Equal(0, first);
-
-            int second = reader.ReadInteger();
-            Assert.Equal(256, second);
-
-            int third = reader.ReadInteger();
-            Assert.Equal(-1, third);
-
-            // Reader reads Big-Endian, BigInteger reads Little-Endian
-            byte[] fourthBytes = reader.ReadIntegerBytes();
-            Array.Reverse(fourthBytes);
-            BigInteger fourth = new BigInteger(fourthBytes);
-            Assert.Equal(BigInteger.Parse("3645759592820458633497613"), fourth);
-
-            // And... done.
-            Assert.False(reader.HasData);
-        }
-
-        [Fact]
-        public static void ReadOids()
-        {
-            byte[] derEncoded =
-            {
-                // Noise
-                0x10, 0x20, 0x30, 0x04, 0x05,
-
-                // Data
-                0x30, 34,
-                0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0B,
-                0x06, 0x03, 0x55, 0x04, 0x03,
-                0x06, 0x09, 0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x15, 0x07,
-                0x06, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22,
-
-                // More noise.
-                0x85, 0x71, 0x23, 0x74, 0x01,
-            };
-
-            DerSequenceReader reader = new DerSequenceReader(derEncoded, 5, derEncoded.Length - 10);
-            Assert.True(reader.HasData);
-            Assert.Equal(34, reader.ContentLength);
-
-            Oid first = reader.ReadOid();
-            Assert.Equal("1.2.840.113549.1.1.11", first.Value);
-
-            Oid second = reader.ReadOid();
-            Assert.Equal("2.5.4.3", second.Value);
-
-            Oid third = reader.ReadOid();
-            Assert.Equal("1.3.6.1.4.1.311.21.7", third.Value);
-
-            Oid fourth = reader.ReadOid();
-            Assert.Equal("1.3.132.0.34", fourth.Value);
-
-            // And... done.
-            Assert.False(reader.HasData);
-        }
-
-        [Theory]
-        [InlineData("Universal 31", "1F1F" + "0C" + "50323031375930324D313844")]
-        [InlineData("Universal 32", "1F20" + "0A" + "5030304830304D303053")]
-        [InlineData("Universal 127", "1F7F" + "01" + "00")]
-        [InlineData("Universal 128", "1F8100" + "01" + "00")]
-        [InlineData("Application 31", "5F1F" + "01" + "00")]
-        [InlineData("Application 32", "5F20" + "01" + "00")]
-        [InlineData("Application 127", "5F7F" + "01" + "00")]
-        [InlineData("Application 128", "5F8100" + "01" + "00")]
-        [InlineData("Context 31", "9F1F" + "01" + "00")]
-        [InlineData("Context 32", "9F20" + "01" + "00")]
-        [InlineData("Context 127", "9F7F" + "01" + "00")]
-        [InlineData("Context 128", "9F8100" + "01" + "00")]
-        [InlineData("Private 31", "DF1F" + "01" + "00")]
-        [InlineData("Private 32", "DF20" + "01" + "00")]
-        [InlineData("Private 127", "DF7F" + "01" + "00")]
-        [InlineData("Private 128", "DF8100" + "01" + "00")]
-        public static void NoSupportForMultiByteTags(string caseName, string hexInput)
-        {
-            byte[] bytes = hexInput.HexToByteArray();
-            DerSequenceReader reader = DerSequenceReader.CreateForPayload(bytes);
-
-            Assert.Throws<CryptographicException>(() => reader.PeekTag());
-            Assert.Throws<CryptographicException>(() => reader.SkipValue());
-            Assert.Throws<CryptographicException>(() => reader.ReadNextEncodedValue());
-        }
-
-        [Theory]
-        [InlineData("0401")]
-        [InlineData("0485")]
-        [InlineData("048500000000")]
-        [InlineData("04850000000000")]
-        [InlineData("048480000000")]
-        [InlineData("0484FFFFFFFF")]
-        [InlineData("0484FFFFFFFA")]
-        [InlineData("0485FF00000000")]
-        public static void InvalidLengthSpecified(string hexInput)
-        {
-            byte[] bytes = hexInput.HexToByteArray();
-            DerSequenceReader reader = DerSequenceReader.CreateForPayload(bytes);
-
-            // Doesn't throw.
-            reader.PeekTag();
-
-            // Since EatTag will have succeeded the reader needs to be reconstructed after each test.
-            Assert.Throws<CryptographicException>(() => reader.SkipValue());
-            reader = DerSequenceReader.CreateForPayload(bytes);
-
-            Assert.Throws<CryptographicException>(() => reader.ReadOctetString());
-            reader = DerSequenceReader.CreateForPayload(bytes);
-
-            Assert.Throws<CryptographicException>(() => reader.ReadNextEncodedValue());
-        }
-
-        [Fact]
-        public static void InteriorLengthTooLong()
-        {
-            byte[] bytes =
-            {
-                // CONSTRUCTED SEQUENCE (8 bytes)
-                0x30, 0x08,
-
-                // CONSTRUCTED SEQUENCE (2 bytes)
-                0x30, 0x02,
-
-                // OCTET STRING (0 bytes)
-                0x04, 0x00,
-
-                // OCTET STRING (after the inner sequence, 3 bytes, but that exceeds the sequence bounds)
-                0x04, 0x03, 0x01, 0x02, 0x03
-            };
-
-            DerSequenceReader reader = new DerSequenceReader(bytes);
-            DerSequenceReader nested = reader.ReadSequence();
-            Assert.Equal(0, nested.ReadOctetString().Length);
-            Assert.False(nested.HasData);
-            Assert.Throws<CryptographicException>(() => reader.ReadOctetString());
-        }
-
-        [Fact]
-        public static void InteriorLengthTooLong_Nested()
-        {
-            byte[] bytes =
-            {
-                // CONSTRUCTED SEQUENCE (9 bytes)
-                0x30, 0x09,
-
-                // CONSTRUCTED SEQUENCE (2 bytes)
-                0x30, 0x02,
-
-                // OCTET STRING (1 byte, but 0 remain for the inner sequence)
-                0x04, 0x01,
-
-                // OCTET STRING (in the outer sequence, after the inner sequence, 3 bytes)
-                0x04, 0x03, 0x01, 0x02, 0x03
-            };
-
-            DerSequenceReader reader = new DerSequenceReader(bytes);
-            DerSequenceReader nested = reader.ReadSequence();
-            Assert.Throws<CryptographicException>(() => nested.ReadOctetString());
-        }
-
-        [Fact]
-        public static void LengthTooLong_ForBounds()
-        {
-            byte[] bytes =
-            {
-                // CONSTRUCTED SEQUENCE (9 bytes)
-                0x30, 0x09,
-
-                // CONSTRUCTED SEQUENCE (2 bytes)
-                0x30, 0x02,
-
-                // OCTET STRING (0 bytes)
-                0x04, 0x00,
-
-                // OCTET STRING (after the inner sequence, 3 bytes)
-                0x04, 0x03, 0x01, 0x02, 0x03
-            };
-
-            Assert.Throws<CryptographicException>(() => new DerSequenceReader(bytes, 0, bytes.Length - 1));
-        }
-    }
-}
index 44818f7..d947000 100644 (file)
@@ -51,8 +51,6 @@
     <Compile Include="AsnEncodedData.cs" />
     <Compile Include="AsnEncodedDataCollectionTests.cs" />
     <Compile Include="Base64TransformsTests.cs" />
-    <Compile Include="DerEncoderTests.cs" />
-    <Compile Include="DerSequenceReaderTests.cs" />
     <Compile Include="Oid.cs" />
     <Compile Include="OidCollectionTests.cs" />
     <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.cs">
     <Compile Include="$(CommonPath)\System\Security\Cryptography\AsnWriter.cs">
       <Link>Common\System\Security\Cryptography\AsnWriter.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\DerEncoder.cs">
-      <Link>Common\System\Security\Cryptography\DerEncoder.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\DerSequenceReader.cs">
-      <Link>Common\System\Security\Cryptography\DerSequenceReader.cs</Link>
-    </Compile>
     <Compile Include="$(CommonTestPath)\System\Security\Cryptography\ByteUtils.cs">
       <Link>CommonTest\System\Security\Cryptography\ByteUtils.cs</Link>
     </Compile>
index 96574b4..cbfe351 100644 (file)
   <data name="Cryptography_Asn_UnusedBitCountRange" xml:space="preserve">
     <value>Unused bit count must be between 0 and 7, inclusive.</value>
   </data>
-  <data name="Cryptography_AsnSerializer_AmbiguousFieldType" xml:space="preserve">
-    <value>Field '{0}' of type '{1}' has ambiguous type '{2}', an attribute derived from AsnTypeAttribute is required.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_AllowNullNonNullable" xml:space="preserve">
-    <value>[Choice].AllowNull=true is not valid because type '{0}' cannot have a null value.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_ConflictingTagMapping" xml:space="preserve">
-    <value>The tag ({0} {1}) for field '{2}' on type '{3}' already is associated in this context with field '{4}' on type '{5}'.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_DefaultValueDisallowed" xml:space="preserve">
-    <value>Field '{0}' on [Choice] type '{1}' has a default value, which is not permitted.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_NoChoiceWasMade" xml:space="preserve">
-    <value>An instance of [Choice] type '{0}' has no non-null fields.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_NonNullableField" xml:space="preserve">
-    <value>Field '{0}' on [Choice] type '{1}' can not be assigned a null value.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_TooManyValues" xml:space="preserve">
-    <value>Fields '{0}' and '{1}' on type '{2}' are both non-null when only one value is permitted.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_TypeCycle" xml:space="preserve">
-    <value>Field '{0}' on [Choice] type '{1}' has introduced a type chain cycle.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_MultipleAsnTypeAttributes" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has multiple attributes deriving from '{2}' when at most one is permitted.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_NoJaggedArrays" xml:space="preserve">
-    <value>Type '{0}' cannot be serialized or deserialized because it is an array of arrays.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_NoMultiDimensionalArrays" xml:space="preserve">
-    <value>Type '{0}' cannot be serialized or deserialized because it is a multi-dimensional array.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_NoOpenTypes" xml:space="preserve">
-    <value>Type '{0}' cannot be serialized or deserialized because it is not sealed or has unbound generic parameters.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Optional_NonNullableField" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' is declared [OptionalValue], but it can not be assigned a null value.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_SetValueException" xml:space="preserve">
-    <value>Unable to set field {0} on type {1}.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_SpecificTagChoice" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has specified an implicit tag value via [ExpectedTag] for [Choice] type '{2}'. ExplicitTag must be true, or the [ExpectedTag] attribute removed.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_UnexpectedTypeForAttribute" xml:space="preserve">
-    <value>Field '{0}' of type '{1}' has an effective type of '{2}' when one of ({3}) was expected.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_UtcTimeTwoDigitYearMaxTooSmall" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has a [UtcTime] TwoDigitYearMax value ({2}) smaller than the minimum (99).</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_UnhandledType" xml:space="preserve">
-    <value>Could not determine how to serialize or deserialize type '{0}'.</value>
-  </data>
   <data name="Cryptography_AsnWriter_EncodeUnbalancedStack" xml:space="preserve">
     <value>Encode cannot be called while a Sequence or SetOf is still open.</value>
   </data>
index 4029810..bfcd96a 100644 (file)
     <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.cs">
       <Link>Common\System\Security\Cryptography\Asn1V2.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.Serializer.cs">
-      <Link>Common\System\Security\Cryptography\Asn1V2.Serializer.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\AsnReader.cs">
       <Link>Common\System\Security\Cryptography\AsnReader.cs</Link>
     </Compile>
       <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs</Link>
       <DependentUpon>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\X509ExtensionAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml</DependentUpon>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\X509ExtensionAsn.manual.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.manual.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml</DependentUpon>
     </Compile>
     <AsnXml Include="System\Security\Cryptography\Pkcs\Asn1\CadesIssuerSerial.xml" />
     <Compile Include="System\Security\Cryptography\Pkcs\Asn1\CadesIssuerSerial.xml.cs">
index 8556a04..7b258db 100644 (file)
@@ -257,7 +257,7 @@ namespace System.Security.Cryptography.Pkcs
             if (extensions != null)
             {
                 tstInfo.Extensions = extensions.OfType<X509Extension>().
-                    Select(ex => new X509ExtensionAsn(ex, copyValue: false)).ToArray();
+                    Select(ex => new X509ExtensionAsn(ex)).ToArray();
             }
 
             using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
index 78bf338..10a952b 100644 (file)
@@ -210,6 +210,35 @@ namespace Internal.Cryptography
         }
     }
 
+    internal static class DictionaryStringHelper
+    {
+        internal static string ReadDirectoryOrIA5String(this AsnReader tavReader)
+        {
+            Asn1Tag tag = tavReader.PeekTag();
+
+            if (tag.TagClass != TagClass.Universal)
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+
+            switch ((UniversalTagNumber)tag.TagValue)
+            {
+                case UniversalTagNumber.BMPString:
+                case UniversalTagNumber.IA5String:
+                case UniversalTagNumber.PrintableString:
+                case UniversalTagNumber.UTF8String:
+                case UniversalTagNumber.T61String:
+                    // .NET's string comparisons start by checking the length, so a trailing
+                    // NULL character which was literally embedded in the DER would cause a
+                    // failure in .NET whereas it wouldn't have with strcmp.
+                    return tavReader.GetCharacterString((UniversalTagNumber)tag.TagValue).TrimEnd('\0');
+                    
+                default:
+                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+        }
+    }
+
     internal struct PinAndClear : IDisposable
     {
         private byte[] _data;
index a532f1a..e0c5604 100644 (file)
@@ -275,79 +275,49 @@ namespace Internal.Cryptography.Pal
                 otherOid == null || otherOid == Oids.UserPrincipalName,
                 $"otherOid ({otherOid}) is not supported");
 
-            // SubjectAltName ::= GeneralNames
-            //
-            // IssuerAltName ::= GeneralNames
-            //
-            // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
-            //
-            // GeneralName ::= CHOICE {
-            //   otherName                       [0]     OtherName,
-            //   rfc822Name                      [1]     IA5String,
-            //   dNSName                         [2]     IA5String,
-            //   x400Address                     [3]     ORAddress,
-            //   directoryName                   [4]     Name,
-            //   ediPartyName                    [5]     EDIPartyName,
-            //   uniformResourceIdentifier       [6]     IA5String,
-            //   iPAddress                       [7]     OCTET STRING,
-            //   registeredID                    [8]     OBJECT IDENTIFIER }
-            //
-            // OtherName::= SEQUENCE {
-            //   type - id    OBJECT IDENTIFIER,
-            //   value[0] EXPLICIT ANY DEFINED BY type - id }
-
-            byte expectedTag = (byte)(DerSequenceReader.ContextSpecificTagFlag | (byte)matchType);
+            AsnReader reader = new AsnReader(extensionBytes, AsnEncodingRules.DER);
+            AsnReader sequenceReader = reader.ReadSequence();
+            reader.ThrowIfNotEmpty();
 
-            if (matchType == GeneralNameType.OtherName)
+            while (sequenceReader.HasData)
             {
-                expectedTag |= DerSequenceReader.ConstructedFlag;
-            }
-
-            DerSequenceReader altNameReader = new DerSequenceReader(extensionBytes);
-
-            while (altNameReader.HasData)
-            {
-                if (altNameReader.PeekTag() != expectedTag)
-                {
-                    altNameReader.SkipValue();
-                    continue;
-                }
+                GeneralNameAsn.Decode(sequenceReader, out GeneralNameAsn generalName);
 
                 switch (matchType)
                 {
                     case GeneralNameType.OtherName:
-                    {
-                        DerSequenceReader otherNameReader = altNameReader.ReadSequence();
-                        string oid = otherNameReader.ReadOidAsString();
-
-                        if (oid == otherOid)
+                        // If the OtherName OID didn't match, move to the next entry.
+                        if (generalName.OtherName.HasValue && generalName.OtherName.Value.TypeId == otherOid)
                         {
-                            // Payload is value[0] EXPLICIT, meaning
-                            // a) it'll be tagged as ContextSpecific0
-                            // b) that's interpretable as a Sequence (EXPLICIT)
-                            // c) the payload will then be retagged as the correct type (EXPLICIT)
-                            if (otherNameReader.PeekTag() != DerSequenceReader.ContextSpecificConstructedTag0)
-                            {
-                                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-                            }
-
-                            otherNameReader = otherNameReader.ReadSequence();
-
                             // Currently only UPN is supported, which is a UTF8 string per
                             // https://msdn.microsoft.com/en-us/library/ff842518.aspx
-                            return otherNameReader.ReadUtf8String();
+                            AsnReader nameReader = new AsnReader(generalName.OtherName.Value.Value, AsnEncodingRules.DER);
+                            string udnName = nameReader.GetCharacterString(UniversalTagNumber.UTF8String);
+                            nameReader.ThrowIfNotEmpty();
+                            return udnName;
                         }
+                        break;
 
-                        // If the OtherName OID didn't match, move to the next entry.
-                        continue;
-                    }
                     case GeneralNameType.Rfc822Name:
+                        if (generalName.Rfc822Name != null)
+                        {
+                            return generalName.Rfc822Name;
+                        }
+                        break;
+
                     case GeneralNameType.DnsName:
+                        if (generalName.DnsName != null)
+                        {
+                            return generalName.DnsName;
+                        }
+                        break;
+
                     case GeneralNameType.UniformResourceIdentifier:
-                        return altNameReader.ReadIA5String();
-                    default:
-                        altNameReader.SkipValue();
-                        continue;
+                        if (generalName.Uri != null)
+                        {
+                            return generalName.Uri;
+                        }
+                        break;
                 }
             }
 
@@ -356,52 +326,26 @@ namespace Internal.Cryptography.Pal
 
         private static IEnumerable<KeyValuePair<string, string>> ReadReverseRdns(X500DistinguishedName name)
         {
-            DerSequenceReader x500NameReader = new DerSequenceReader(name.RawData);
-            var rdnReaders = new Stack<DerSequenceReader>();
+            AsnReader x500NameReader = new AsnReader(name.RawData, AsnEncodingRules.DER);
+            AsnReader sequenceReader = x500NameReader.ReadSequence();
+            var rdnReaders = new Stack<AsnReader>();
+            x500NameReader.ThrowIfNotEmpty();
 
-            while (x500NameReader.HasData)
+            while (sequenceReader.HasData)
             {
-                rdnReaders.Push(x500NameReader.ReadSet());
+                rdnReaders.Push(sequenceReader.ReadSetOf());
             }
 
-
             while (rdnReaders.Count > 0)
             {
-                DerSequenceReader rdnReader = rdnReaders.Pop();
-
+                AsnReader rdnReader = rdnReaders.Pop();
                 while (rdnReader.HasData)
                 {
-                    DerSequenceReader tavReader = rdnReader.ReadSequence();
-                    string oid = tavReader.ReadOidAsString();
-
-                    var tag = (DerSequenceReader.DerTag)tavReader.PeekTag();
-                    string value = null;
-
-                    switch (tag)
-                    {
-                        case DerSequenceReader.DerTag.BMPString:
-                            value = tavReader.ReadBMPString();
-                            break;
-                        case DerSequenceReader.DerTag.IA5String:
-                            value = tavReader.ReadIA5String();
-                            break;
-                        case DerSequenceReader.DerTag.PrintableString:
-                            value = tavReader.ReadPrintableString();
-                            break;
-                        case DerSequenceReader.DerTag.UTF8String:
-                            value = tavReader.ReadUtf8String();
-                            break;
-                        case DerSequenceReader.DerTag.T61String:
-                            value = tavReader.ReadT61String();
-                            break;
-
-                        // Ignore anything we don't know how to read.
-                    }
-
-                    if (value != null)
-                    {
-                        yield return new KeyValuePair<string, string>(oid, value);
-                    }
+                    AsnReader tavReader = rdnReader.ReadSequence();
+                    string oid = tavReader.ReadObjectIdentifierAsString();
+                    string value = tavReader.ReadDirectoryOrIA5String();
+                    tavReader.ThrowIfNotEmpty();
+                    yield return new KeyValuePair<string, string>(oid, value);
                 }
             }
         }
index 79b7730..0968810 100644 (file)
@@ -4,17 +4,14 @@
 
 using System;
 using System.Collections.Generic;
+using System.Runtime.InteropServices;
 using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
 using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography.X509Certificates.Asn1;
 
 namespace Internal.Cryptography.Pal
 {
-    internal struct CertificatePolicyMapping
-    {
-        public string IssuerDomainPolicy;
-        public string SubjectDomainPolicy;
-    }
-
     internal sealed class CertificatePolicy
     {
         public bool ImplicitAnyCertificatePolicy { get; set; }
@@ -24,7 +21,7 @@ namespace Internal.Cryptography.Pal
         public bool SpecifiedAnyApplicationPolicy { get; set; }
         public ISet<string> DeclaredApplicationPolicies { get; set; }
         public int? InhibitAnyDepth { get; set; }
-        public List<CertificatePolicyMapping> PolicyMapping { get; set; }
+        public List<CertificatePolicyMappingAsn> PolicyMapping { get; set; }
         public int? InhibitMappingDepth { get; set; }
         public int? RequireExplicitPolicyDepth { get; set; }
 
@@ -88,8 +85,7 @@ namespace Internal.Cryptography.Pal
                 {
                     for (int iMapping = 0; iMapping < policy.PolicyMapping.Count; iMapping++)
                     {
-                        CertificatePolicyMapping mapping = policy.PolicyMapping[iMapping];
-
+                        CertificatePolicyMappingAsn mapping = policy.PolicyMapping[iMapping];
                         if (StringComparer.Ordinal.Equals(mapping.IssuerDomainPolicy, oidToCheck))
                         {
                             nextOid = mapping.SubjectDomainPolicy;
@@ -293,40 +289,21 @@ namespace Internal.Cryptography.Pal
 
         private static int ReadInhibitAnyPolicyExtension(X509Extension extension)
         {
-            DerSequenceReader reader = DerSequenceReader.CreateForPayload(extension.RawData);
-            return reader.ReadInteger();
+            AsnReader reader = new AsnReader(extension.RawData, AsnEncodingRules.DER);
+            int inhibitAnyPolicy;
+            reader.TryReadInt32(out inhibitAnyPolicy);
+            reader.ThrowIfNotEmpty();
+            return inhibitAnyPolicy;
         }
 
         private static void ReadCertPolicyConstraintsExtension(X509Extension extension, CertificatePolicy policy)
         {
-            DerSequenceReader reader = new DerSequenceReader(extension.RawData);
+            PolicyConstraintsAsn constraints = PolicyConstraintsAsn.Decode(
+                extension.RawData,
+                AsnEncodingRules.DER);
 
-            while (reader.HasData)
-            {
-                // Policy Constraints context specific tag values are defined in RFC 3280 4.2.1.12,
-                // and restated (unchanged) in RFC 5280 4.2.1.11.
-                switch (reader.PeekTag())
-                {
-                    case DerSequenceReader.ContextSpecificTagFlag | 0:
-                        policy.RequireExplicitPolicyDepth = reader.ReadInteger();
-                        break;
-                    case DerSequenceReader.ContextSpecificTagFlag | 1:
-                        policy.InhibitMappingDepth = reader.ReadInteger();
-                        break;
-                    default:
-                        if (extension.Critical)
-                        {
-                            // If an unknown value is read, but we're marked as critical,
-                            // then we don't know what we're doing and MUST fail validation
-                            // (RFC 3280).
-                            // If it isn't critical then it means we're allowed to be ignorant
-                            // of data defined more recently than we understand.
-                            throw new CryptographicException();
-                        }
-
-                        break;
-                }
-            }
+            policy.RequireExplicitPolicyDepth = constraints.RequireExplicitPolicyDepth;
+            policy.InhibitMappingDepth = constraints.InhibitMappingDepth;
         }
 
         private static ISet<string> ReadExtendedKeyUsageExtension(X509Extension extension)
@@ -344,13 +321,15 @@ namespace Internal.Cryptography.Pal
 
         internal static ISet<string> ReadCertPolicyExtension(X509Extension extension)
         {
-            DerSequenceReader reader = new DerSequenceReader(extension.RawData);
-            HashSet<string> policies = new HashSet<string>();
+            AsnReader reader = new AsnReader(extension.RawData, AsnEncodingRules.DER);
+            AsnReader sequenceReader = reader.ReadSequence();
+            reader.ThrowIfNotEmpty();
 
-            while (reader.HasData)
+            HashSet<string> policies = new HashSet<string>();
+            while (sequenceReader.HasData)
             {
-                DerSequenceReader policyInformation = reader.ReadSequence();
-                policies.Add(policyInformation.ReadOidAsString());
+                PolicyInformationAsn.Decode(sequenceReader, out PolicyInformationAsn policyInformation);
+                policies.Add(policyInformation.PolicyIdentifier);
 
                 // There is an optional policy qualifier here, but it is for information
                 // purposes, there is no logic that would be changed.
@@ -362,20 +341,17 @@ namespace Internal.Cryptography.Pal
             return policies;
         }
 
-        private static List<CertificatePolicyMapping> ReadCertPolicyMappingsExtension(X509Extension extension)
+        private static List<CertificatePolicyMappingAsn> ReadCertPolicyMappingsExtension(X509Extension extension)
         {
-            DerSequenceReader reader = new DerSequenceReader(extension.RawData);
-            List<CertificatePolicyMapping> mappings = new List<CertificatePolicyMapping>();
+            AsnReader reader = new AsnReader(extension.RawData, AsnEncodingRules.DER);
+            AsnReader sequenceReader = reader.ReadSequence();
+            reader.ThrowIfNotEmpty();
 
-            while (reader.HasData)
+            List<CertificatePolicyMappingAsn> mappings = new List<CertificatePolicyMappingAsn>();
+            while (sequenceReader.HasData)
             {
-                DerSequenceReader mappingSequence = reader.ReadSequence();
-                mappings.Add(
-                    new CertificatePolicyMapping
-                    {
-                        IssuerDomainPolicy = mappingSequence.ReadOidAsString(),
-                        SubjectDomainPolicy = mappingSequence.ReadOidAsString(),
-                    });
+                CertificatePolicyMappingAsn.Decode(sequenceReader, out CertificatePolicyMappingAsn mapping);
+                mappings.Add(mapping);
             }
 
             return mappings;
index fadf117..e7eeae3 100644 (file)
@@ -6,7 +6,9 @@ using System;
 using System.Diagnostics;
 using System.IO;
 using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
 using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography.X509Certificates.Asn1;
 using Microsoft.Win32.SafeHandles;
 
 namespace Internal.Cryptography.Pal
@@ -209,82 +211,28 @@ namespace Internal.Cryptography.Pal
                 return null;
             }
 
-            // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
-            //
-            // DistributionPoint ::= SEQUENCE {
-            //    distributionPoint       [0]     DistributionPointName OPTIONAL,
-            //    reasons                 [1]     ReasonFlags OPTIONAL,
-            //    cRLIssuer               [2]     GeneralNames OPTIONAL }
-            //
-            // DistributionPointName ::= CHOICE {
-            //    fullName                [0]     GeneralNames,
-            //    nameRelativeToCRLIssuer [1]     RelativeDistinguishedName }
-            //
-            // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
-            //
-            // GeneralName ::= CHOICE {
-            //    otherName                       [0]     OtherName,
-            //    rfc822Name                      [1]     IA5String,
-            //    dNSName                         [2]     IA5String,
-            //    x400Address                     [3]     ORAddress,
-            //    directoryName                   [4]     Name,
-            //    ediPartyName                    [5]     EDIPartyName,
-            //    uniformResourceIdentifier       [6]     IA5String,
-            //    iPAddress                       [7]     OCTET STRING,
-            //    registeredID                    [8]     OBJECT IDENTIFIER }
-
-            DerSequenceReader cdpSequence = new DerSequenceReader(crlDistributionPoints);
-
-            while (cdpSequence.HasData)
-            {
-                const byte ContextSpecificFlag = 0x80;
-                const byte ContextSpecific0 = ContextSpecificFlag;
-                const byte ConstructedFlag = 0x20;
-                const byte ContextSpecificConstructed0 = ContextSpecific0 | ConstructedFlag;
-                const byte GeneralNameUri = ContextSpecificFlag | 0x06;
+            AsnReader reader = new AsnReader(crlDistributionPoints, AsnEncodingRules.DER);
+            AsnReader sequenceReader = reader.ReadSequence();
+            reader.ThrowIfNotEmpty();
 
-                DerSequenceReader distributionPointReader = cdpSequence.ReadSequence();
-                byte tag = distributionPointReader.PeekTag();
+            while (sequenceReader.HasData)
+            {
+                DistributionPointAsn.Decode(sequenceReader, out DistributionPointAsn distributionPoint);
 
                 // Only distributionPoint is supported
-                if (tag != ContextSpecificConstructed0)
-                {
-                    continue;
-                }
-
-                // The DistributionPointName is a CHOICE, not a SEQUENCE, but the reader is the same.
-                DerSequenceReader dpNameReader = distributionPointReader.ReadSequence();
-                tag = dpNameReader.PeekTag();
-
-                // Only fullName is supported,
-                // nameRelativeToCRLIssuer is for LDAP-based lookup.
-                if (tag != ContextSpecificConstructed0)
-                {
-                    continue;
-                }
-
-                DerSequenceReader fullNameReader = dpNameReader.ReadSequence();
-
-                while (fullNameReader.HasData)
+                // Only fullName is supported, nameRelativeToCRLIssuer is for LDAP-based lookup.
+                if (distributionPoint.DistributionPoint.HasValue &&
+                    distributionPoint.DistributionPoint.Value.FullName != null)
                 {
-                    tag = fullNameReader.PeekTag();
-
-                    if (tag != GeneralNameUri)
+                    foreach (GeneralNameAsn name in distributionPoint.DistributionPoint.Value.FullName)
                     {
-                        fullNameReader.SkipValue();
-                        continue;
-                    }
-
-                    string uri = fullNameReader.ReadIA5String();
-
-                    Uri parsedUri = new Uri(uri);
-
-                    if (!StringComparer.Ordinal.Equals(parsedUri.Scheme, "http"))
-                    {
-                        continue;
+                        if (name.Uri != null &&
+                            Uri.TryCreate(name.Uri, UriKind.Absolute, out Uri uri) &&
+                            uri.Scheme == "http")
+                        {
+                            return name.Uri;
+                        }
                     }
-
-                    return uri;
                 }
             }
 
index a70bf14..aae9e68 100644 (file)
@@ -7,7 +7,9 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.Numerics;
 using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
 using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography.X509Certificates.Asn1;
 
 namespace Internal.Cryptography.Pal
 {
@@ -123,37 +125,6 @@ namespace Internal.Cryptography.Pal
             FindCore(cert => cert.NotAfter < normalized);
         }
 
-        private string DerStringToManagedString(byte[] anyString)
-        {
-            DerSequenceReader reader = DerSequenceReader.CreateForPayload(anyString);
-
-            var tag = (DerSequenceReader.DerTag)reader.PeekTag();
-            string value = null;
-
-            switch (tag)
-            {
-                case DerSequenceReader.DerTag.BMPString:
-                    value = reader.ReadBMPString();
-                    break;
-                case DerSequenceReader.DerTag.IA5String:
-                    value = reader.ReadIA5String();
-                    break;
-                case DerSequenceReader.DerTag.PrintableString:
-                    value = reader.ReadPrintableString();
-                    break;
-                case DerSequenceReader.DerTag.UTF8String:
-                    value = reader.ReadUtf8String();
-                    break;
-                case DerSequenceReader.DerTag.T61String:
-                    value = reader.ReadT61String();
-                    break;
-
-                // Ignore anything we don't know how to read.
-            }
-
-            return value;
-        }
-
         public void FindByTemplateName(string templateName)
         {
             FindCore(
@@ -164,7 +135,9 @@ namespace Internal.Cryptography.Pal
                     if (ext != null)
                     {
                         // Try a V1 template structure, just a string:
-                        string decodedName = DerStringToManagedString(ext.RawData);
+                        AsnReader reader = new AsnReader(ext.RawData, AsnEncodingRules.DER);
+                        string decodedName = reader.ReadDirectoryOrIA5String();
+                        reader.ThrowIfNotEmpty();
 
                         // If this doesn't match, maybe a V2 template will
                         if (StringComparer.OrdinalIgnoreCase.Equals(templateName, decodedName))
@@ -177,21 +150,10 @@ namespace Internal.Cryptography.Pal
 
                     if (ext != null)
                     {
-                        DerSequenceReader reader = new DerSequenceReader(ext.RawData);
-                        // SEQUENCE (
-                        //     OID oid,
-                        //     INTEGER major,
-                        //     INTEGER minor OPTIONAL
-                        //  )
-
-                        if (reader.PeekTag() == (byte)DerSequenceReader.DerTag.ObjectIdentifier)
+                        CertificateTemplateAsn template = CertificateTemplateAsn.Decode(ext.RawData, AsnEncodingRules.DER);
+                        if (StringComparer.Ordinal.Equals(templateName, template.TemplateID))
                         {
-                            Oid oid = reader.ReadOid();
-
-                            if (StringComparer.Ordinal.Equals(templateName, oid.Value))
-                            {
-                                return true;
-                            }
+                            return true;
                         }
                     }
 
index 7c0040a..47f8301 100644 (file)
@@ -6,7 +6,9 @@ using System;
 using System.Collections.Generic;
 using System.Diagnostics;
 using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
 using System.Security.Cryptography.X509Certificates;
+using System.Security.Cryptography.X509Certificates.Asn1;
 using Microsoft.Win32.SafeHandles;
 
 namespace Internal.Cryptography.Pal
@@ -595,36 +597,22 @@ namespace Internal.Cryptography.Pal
 
         internal static string FindHttpAiaRecord(byte[] authorityInformationAccess, string recordTypeOid)
         {
-            DerSequenceReader reader = new DerSequenceReader(authorityInformationAccess);
+            AsnReader reader = new AsnReader(authorityInformationAccess, AsnEncodingRules.DER);
+            AsnReader sequenceReader = reader.ReadSequence();
+            reader.ThrowIfNotEmpty();
 
-            while (reader.HasData)
+            while (sequenceReader.HasData)
             {
-                DerSequenceReader innerReader = reader.ReadSequence();
-
-                // If the sequence's first element is a sequence, unwrap it.
-                if (innerReader.PeekTag() == ConstructedSequenceTagId)
-                {
-                    innerReader = innerReader.ReadSequence();
-                }
-
-                Oid oid = innerReader.ReadOid();
-
-                if (StringComparer.Ordinal.Equals(oid.Value, recordTypeOid))
+                AccessDescriptionAsn.Decode(sequenceReader, out AccessDescriptionAsn description);
+                if (StringComparer.Ordinal.Equals(description.AccessMethod, recordTypeOid))
                 {
-                    string uri = innerReader.ReadIA5String();
-
-                    Uri parsedUri;
-                    if (!Uri.TryCreate(uri, UriKind.Absolute, out parsedUri))
+                    GeneralNameAsn name = description.AccessLocation;
+                    if (name.Uri != null &&
+                        Uri.TryCreate(name.Uri, UriKind.Absolute, out Uri uri) &&
+                        uri.Scheme == "http")
                     {
-                        continue;
-                    }
-
-                    if (!StringComparer.Ordinal.Equals(parsedUri.Scheme, "http"))
-                    {
-                        continue;
+                        return name.Uri;
                     }
-
-                    return uri;
                 }
             }
 
index 83e561d..1fc4ee9 100644 (file)
@@ -5,6 +5,7 @@
 using System;
 using System.Diagnostics;
 using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
 using System.Security.Cryptography.X509Certificates;
 using Microsoft.Win32.SafeHandles;
 
@@ -267,71 +268,19 @@ namespace Internal.Cryptography.Pal
 
         private static DSA BuildDsaPublicKey(byte[] encodedKey, byte[] encodedParameters)
         {
-            // Dss-Parms ::= SEQUENCE { 
-            //   p INTEGER, 
-            //   q INTEGER, 
-            //   g INTEGER 
-            // } 
-
-            // The encodedKey value is a DER INTEGER representing the Y value
-
-            DerSequenceReader parametersReader = new DerSequenceReader(encodedParameters);
-            DerSequenceReader keyReader = DerSequenceReader.CreateForPayload(encodedKey);
-
-            DSAParameters parameters = new DSAParameters();
-
-            // While this could use the object initializer, the read modifies the data stream, so
-            // leaving these in flat call for clarity.
-            parameters.P = parametersReader.ReadIntegerBytes();
-            parameters.Q = parametersReader.ReadIntegerBytes();
-            parameters.G = parametersReader.ReadIntegerBytes();
-            parameters.Y = keyReader.ReadIntegerBytes();
-
-            // Make the structure look like it would from Windows / .NET Framework
-            TrimPaddingByte(ref parameters.P);
-            TrimPaddingByte(ref parameters.Q);
-
-            PadOrTrim(ref parameters.G, parameters.P.Length);
-            PadOrTrim(ref parameters.Y, parameters.P.Length);
-
-            DSA dsa = new DSAOpenSsl();
-            dsa.ImportParameters(parameters);
-            return dsa;
-        }
-
-        private static void TrimPaddingByte(ref byte[] data)
-        {
-            if (data.Length > 0 && data[0] == 0)
+            SubjectPublicKeyInfoAsn spki = new SubjectPublicKeyInfoAsn
             {
-                byte[] tmp = new byte[data.Length - 1];
-                Buffer.BlockCopy(data, 1, tmp, 0, tmp.Length);
-                data = tmp;
-            }
-        }
+                Algorithm = new AlgorithmIdentifierAsn { Algorithm = new Oid(Oids.Dsa), Parameters = encodedParameters },
+                SubjectPublicKey = encodedKey,
+            };
 
-        private static void PadOrTrim(ref byte[] data, int dataLen)
-        {
-            if (data.Length == dataLen)
-                return;
-
-            if (data.Length < dataLen)
+            using (AsnWriter writer = new AsnWriter(AsnEncodingRules.DER))
             {
-                // Add leading 0s
-                byte[] tmp = new byte[dataLen];
-                Buffer.BlockCopy(data, 0, tmp, dataLen - data.Length, dataLen);
-                data = tmp;
-                return;
+                DSA dsa = new DSAOpenSsl();
+                spki.Encode(writer);
+                dsa.ImportSubjectPublicKeyInfo(writer.EncodeAsSpan(), out _);
+                return dsa;
             }
-
-            if (data.Length == dataLen + 1 && data[0] == 0)
-            {
-                byte[] tmp = new byte[dataLen];
-                Buffer.BlockCopy(data, 1, tmp, 0, dataLen);
-                data = tmp;
-                return;
-            }
-
-            throw new CryptographicException();
         }
     }
 }
index c5788ba..44a6334 100644 (file)
@@ -91,7 +91,7 @@ namespace Internal.Cryptography.Pal
                 {
                     AsnReader tavReader = rdnReader.ReadSequence();
                     string oid = tavReader.ReadObjectIdentifierAsString();
-                    string attributeValue = ReadString(tavReader);
+                    string attributeValue = tavReader.ReadDirectoryOrIA5String();
 
                     tavReader.ThrowIfNotEmpty();
 
@@ -137,27 +137,5 @@ namespace Internal.Cryptography.Pal
 
             return decodedName.ToString();
         }
-
-        private static string ReadString(AsnReader tavReader)
-        {
-            Asn1Tag tag = tavReader.PeekTag();
-
-            if (tag.TagClass != TagClass.Universal)
-            {
-                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-
-            switch ((UniversalTagNumber)tag.TagValue)
-            {
-                case UniversalTagNumber.BMPString:
-                case UniversalTagNumber.IA5String:
-                case UniversalTagNumber.PrintableString:
-                case UniversalTagNumber.UTF8String:
-                case UniversalTagNumber.T61String:
-                    return tavReader.GetCharacterString((UniversalTagNumber)tag.TagValue);
-                default:
-                    throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
-            }
-        }
     }
 }
index ba878d0..8d9cede 100644 (file)
   <data name="Cryptography_Asn_UnusedBitCountRange" xml:space="preserve">
     <value>Unused bit count must be between 0 and 7, inclusive.</value>
   </data>
-  <data name="Cryptography_AsnSerializer_AmbiguousFieldType" xml:space="preserve">
-    <value>Field '{0}' of type '{1}' has ambiguous type '{2}', an attribute derived from AsnTypeAttribute is required.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_AllowNullNonNullable" xml:space="preserve">
-    <value>[Choice].AllowNull=true is not valid because type '{0}' cannot have a null value.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_ConflictingTagMapping" xml:space="preserve">
-    <value>The tag ({0} {1}) for field '{2}' on type '{3}' already is associated in this context with field '{4}' on type '{5}'.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_DefaultValueDisallowed" xml:space="preserve">
-    <value>Field '{0}' on [Choice] type '{1}' has a default value, which is not permitted.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_NoChoiceWasMade" xml:space="preserve">
-    <value>An instance of [Choice] type '{0}' has no non-null fields.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_NonNullableField" xml:space="preserve">
-    <value>Field '{0}' on [Choice] type '{1}' can not be assigned a null value.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_TooManyValues" xml:space="preserve">
-    <value>Fields '{0}' and '{1}' on type '{2}' are both non-null when only one value is permitted.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Choice_TypeCycle" xml:space="preserve">
-    <value>Field '{0}' on [Choice] type '{1}' has introduced a type chain cycle.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_MultipleAsnTypeAttributes" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has multiple attributes deriving from '{2}' when at most one is permitted.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_NoJaggedArrays" xml:space="preserve">
-    <value>Type '{0}' cannot be serialized or deserialized because it is an array of arrays.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_NoMultiDimensionalArrays" xml:space="preserve">
-    <value>Type '{0}' cannot be serialized or deserialized because it is a multi-dimensional array.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_NoOpenTypes" xml:space="preserve">
-    <value>Type '{0}' cannot be serialized or deserialized because it is not sealed or has unbound generic parameters.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_Optional_NonNullableField" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' is declared [OptionalValue], but it can not be assigned a null value.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_SetValueException" xml:space="preserve">
-    <value>Unable to set field {0} on type {1}.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_SpecificTagChoice" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has specified an implicit tag value via [ExpectedTag] for [Choice] type '{2}'. ExplicitTag must be true, or the [ExpectedTag] attribute removed.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_UnexpectedTypeForAttribute" xml:space="preserve">
-    <value>Field '{0}' of type '{1}' has an effective type of '{2}' when one of ({3}) was expected.</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_UtcTimeTwoDigitYearMaxTooSmall" xml:space="preserve">
-    <value>Field '{0}' on type '{1}' has a [UtcTime] TwoDigitYearMax value ({2}) smaller than the minimum (99).</value>
-  </data>
-  <data name="Cryptography_AsnSerializer_UnhandledType" xml:space="preserve">
-    <value>Could not determine how to serialize or deserialize type '{0}'.</value>
-  </data>
   <data name="Cryptography_AsnWriter_EncodeUnbalancedStack" xml:space="preserve">
     <value>Encode cannot be called while a Sequence or SetOf is still open.</value>
   </data>
index db54b57..15b9243 100644 (file)
     <Compile Include="$(CommonPath)\Microsoft\Win32\SafeHandles\SafeHandleCache.cs">
       <Link>Common\Microsoft\Win32\SafeHandles\SafeHandleCache.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\DerEncoder.cs">
-      <Link>Common\System\Security\Cryptography\DerEncoder.cs</Link>
-    </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\DerSequenceReader.cs">
-      <Link>Common\System\Security\Cryptography\DerSequenceReader.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.cs">
       <Link>Common\System\Security\Cryptography\Asn1V2.cs</Link>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1V2.Serializer.cs">
-      <Link>Common\System\Security\Cryptography\Asn1V2.Serializer.cs</Link>
-    </Compile>
     <Compile Include="$(CommonPath)\System\Security\Cryptography\AsnReader.cs">
       <Link>Common\System\Security\Cryptography\AsnReader.cs</Link>
     </Compile>
       <Link>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml.cs</Link>
       <DependentUpon>Common\System\Security\Cryptography\Asn1\SubjectPublicKeyInfoAsn.xml</DependentUpon>
     </Compile>
-    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\X509ExtensionAsn.cs">
-      <Link>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.cs</Link>
+    <AsnXml Include="$(CommonPath)\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml">
+      <Link>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml</Link>
+    </AsnXml>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml</DependentUpon>
+    </Compile>
+    <Compile Include="$(CommonPath)\System\Security\Cryptography\Asn1\X509ExtensionAsn.manual.cs">
+      <Link>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.manual.cs</Link>
+      <DependentUpon>Common\System\Security\Cryptography\Asn1\X509ExtensionAsn.xml</DependentUpon>
     </Compile>
     <Compile Include="$(CommonPath)\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs">
       <Link>Common\Internal\Cryptography\AsymmetricAlgorithmHelpers.Der.cs</Link>
       <DependentUpon>System\Security\Cryptography\X509Certificates\Asn1\X501AttributeAsn.xml</DependentUpon>
     </Compile>
     <Compile Include="System\Security\Cryptography\X509Certificates\Asn1\X501AttributeAsn.manual.cs" />
+    <AsnXml Include="System\Security\Cryptography\X509Certificates\Asn1\AccessDescriptionAsn.xml" />
+    <Compile Include="System\Security\Cryptography\X509Certificates\Asn1\AccessDescriptionAsn.xml.cs">
+      <DependentUpon>System\Security\Cryptography\X509Certificates\Asn1\AccessDescriptionAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="System\Security\Cryptography\X509Certificates\Asn1\CertificatePolicyMappingAsn.xml" />
+    <Compile Include="System\Security\Cryptography\X509Certificates\Asn1\CertificatePolicyMappingAsn.xml.cs">
+      <DependentUpon>System\Security\Cryptography\X509Certificates\Asn1\CertificatePolicyMappingAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="System\Security\Cryptography\X509Certificates\Asn1\CertificateTemplateAsn.xml" />
+    <Compile Include="System\Security\Cryptography\X509Certificates\Asn1\CertificateTemplateAsn.xml.cs">
+      <DependentUpon>System\Security\Cryptography\X509Certificates\Asn1\CertificateTemplateAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="System\Security\Cryptography\X509Certificates\Asn1\PolicyConstraintsAsn.xml" />
+    <Compile Include="System\Security\Cryptography\X509Certificates\Asn1\PolicyConstraintsAsn.xml.cs">
+      <DependentUpon>System\Security\Cryptography\X509Certificates\Asn1\PolicyConstraintsAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="System\Security\Cryptography\X509Certificates\Asn1\PolicyInformationAsn.xml" />
+    <Compile Include="System\Security\Cryptography\X509Certificates\Asn1\PolicyInformationAsn.xml.cs">
+      <DependentUpon>System\Security\Cryptography\X509Certificates\Asn1\PolicyInformationAsn.xml</DependentUpon>
+    </Compile>
   </ItemGroup>
   <ItemGroup Condition=" '$(TargetsWindows)' == 'true'">
     <Compile Include="Internal\Cryptography\Pal.Windows\CertificatePal.cs" />
     <Compile Include="Microsoft\Win32\SafeHandles\SafePasswordHandle.Unix.cs" />
   </ItemGroup>
   <ItemGroup Condition=" '$(TargetsUnix)' == 'true' AND '$(TargetsOSX)' != 'true' ">
+    <AsnXml Include="System\Security\Cryptography\X509Certificates\Asn1\DistributionPointAsn.xml" />
+    <Compile Include="System\Security\Cryptography\X509Certificates\Asn1\DistributionPointAsn.xml.cs">
+      <DependentUpon>System\Security\Cryptography\X509Certificates\Asn1\DistributionPointAsn.xml</DependentUpon>
+    </Compile>
+    <AsnXml Include="System\Security\Cryptography\X509Certificates\Asn1\DistributionPointNameAsn.xml" />
+    <Compile Include="System\Security\Cryptography\X509Certificates\Asn1\DistributionPointNameAsn.xml.cs">
+      <DependentUpon>System\Security\Cryptography\X509Certificates\Asn1\DistributionPointNameAsn.xml</DependentUpon>
+    </Compile>
+    <Compile Include="System\Security\Cryptography\X509Certificates\Asn1\ReasonFlagsAsn.cs" />
     <Compile Include="Internal\Cryptography\Pal.Unix\CertCollectionLoader.cs" />
     <Compile Include="Internal\Cryptography\Pal.Unix\CertificateAssetDownloader.cs" />
     <Compile Include="Internal\Cryptography\Pal.Unix\CertificatePal.cs" />
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/AccessDescriptionAsn.xml b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/AccessDescriptionAsn.xml
new file mode 100644 (file)
index 0000000..5e77070
--- /dev/null
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="AccessDescriptionAsn"
+  namespace="System.Security.Cryptography.X509Certificates.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc5280#section-4.2.2.1
+
+    AccessDescription  ::=  SEQUENCE {
+        accessMethod          OBJECT IDENTIFIER,
+        accessLocation        GeneralName
+    }
+  -->
+  <asn:ObjectIdentifier name="AccessMethod" backingType="string" />
+  <asn:AsnType name="AccessLocation" typeName="System.Security.Cryptography.Asn1.GeneralNameAsn" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/AccessDescriptionAsn.xml.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/AccessDescriptionAsn.xml.cs
new file mode 100644 (file)
index 0000000..8227c02
--- /dev/null
@@ -0,0 +1,64 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.X509Certificates.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct AccessDescriptionAsn
+    {
+        internal string AccessMethod;
+        internal System.Security.Cryptography.Asn1.GeneralNameAsn AccessLocation;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteObjectIdentifier(AccessMethod);
+            AccessLocation.Encode(writer);
+            writer.PopSequence(tag);
+        }
+
+        internal static AccessDescriptionAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static AccessDescriptionAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out AccessDescriptionAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out AccessDescriptionAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out AccessDescriptionAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+            decoded.AccessMethod = sequenceReader.ReadObjectIdentifierAsString();
+            System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(sequenceReader, out decoded.AccessLocation);
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificatePolicyMappingAsn.xml b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificatePolicyMappingAsn.xml
new file mode 100644 (file)
index 0000000..cf15ba9
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="CertificatePolicyMappingAsn"
+  namespace="System.Security.Cryptography.X509Certificates.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc5280#section-4.2.1.5
+
+    PolicyMappings ::= SEQUENCE SIZE (1..MAX) OF SEQUENCE {
+        issuerDomainPolicy      CertPolicyId,
+        subjectDomainPolicy     CertPolicyId
+    }
+
+    CertPolicyId ::= OBJECT IDENTIFIER
+  -->
+  <asn:ObjectIdentifier name="IssuerDomainPolicy" backingType="string" />
+  <asn:ObjectIdentifier name="SubjectDomainPolicy" backingType="string" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificatePolicyMappingAsn.xml.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificatePolicyMappingAsn.xml.cs
new file mode 100644 (file)
index 0000000..d257b89
--- /dev/null
@@ -0,0 +1,64 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.X509Certificates.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct CertificatePolicyMappingAsn
+    {
+        internal string IssuerDomainPolicy;
+        internal string SubjectDomainPolicy;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteObjectIdentifier(IssuerDomainPolicy);
+            writer.WriteObjectIdentifier(SubjectDomainPolicy);
+            writer.PopSequence(tag);
+        }
+
+        internal static CertificatePolicyMappingAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static CertificatePolicyMappingAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out CertificatePolicyMappingAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out CertificatePolicyMappingAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CertificatePolicyMappingAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+            decoded.IssuerDomainPolicy = sequenceReader.ReadObjectIdentifierAsString();
+            decoded.SubjectDomainPolicy = sequenceReader.ReadObjectIdentifierAsString();
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificateTemplateAsn.xml b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificateTemplateAsn.xml
new file mode 100644 (file)
index 0000000..28a708f
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="CertificateTemplateAsn"
+  namespace="System.Security.Cryptography.X509Certificates.Asn1">
+
+  <!--
+    Microsoft extension (1.3.6.1.4.1.311.21.7)
+
+    TemplateVersion ::= INTEGER
+
+    CertificateTemplate ::= SEQUENCE {
+        templateID OBJECT IDENTIFIER,
+        templateMajorVersion TemplateVersion,
+        templateMinorVersion TemplateVersion OPTIONAL
+    }
+  -->
+  <asn:ObjectIdentifier name="TemplateID" backingType="string" />
+  <asn:Integer name="TemplateMajorVersion" backingType="int" />
+  <asn:Integer name="TemplateMinorVersion" backingType="int" optional="true" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificateTemplateAsn.xml.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificateTemplateAsn.xml.cs
new file mode 100644 (file)
index 0000000..04b9a4d
--- /dev/null
@@ -0,0 +1,91 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.X509Certificates.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct CertificateTemplateAsn
+    {
+        internal string TemplateID;
+        internal int TemplateMajorVersion;
+        internal int? TemplateMinorVersion;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteObjectIdentifier(TemplateID);
+            writer.WriteInteger(TemplateMajorVersion);
+
+            if (TemplateMinorVersion.HasValue)
+            {
+                writer.WriteInteger(TemplateMinorVersion.Value);
+            }
+
+            writer.PopSequence(tag);
+        }
+
+        internal static CertificateTemplateAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static CertificateTemplateAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out CertificateTemplateAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out CertificateTemplateAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CertificateTemplateAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+            decoded.TemplateID = sequenceReader.ReadObjectIdentifierAsString();
+
+            if (!sequenceReader.TryReadInt32(out decoded.TemplateMajorVersion))
+            {
+                sequenceReader.ThrowIfNotEmpty();
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
+            {
+
+                if (sequenceReader.TryReadInt32(out int tmpTemplateMinorVersion))
+                {
+                    decoded.TemplateMinorVersion = tmpTemplateMinorVersion;
+                }
+                else
+                {
+                    sequenceReader.ThrowIfNotEmpty();
+                }
+
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointAsn.xml b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointAsn.xml
new file mode 100644 (file)
index 0000000..a1a5860
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="DistributionPointAsn"
+  namespace="System.Security.Cryptography.X509Certificates.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc5280#section-4.2.1.13
+
+    DistributionPoint ::= SEQUENCE {
+        distributionPoint       [0]     DistributionPointName OPTIONAL,
+        reasons                 [1]     ReasonFlags OPTIONAL,
+        cRLIssuer               [2]     GeneralNames OPTIONAL
+    }
+  -->
+  <asn:AsnType name="DistributionPoint" typeName="System.Security.Cryptography.X509Certificates.Asn1.DistributionPointNameAsn" explicitTag="0" optional="true" />
+  <asn:NamedBitList name="Reasons" backingType="System.Security.Cryptography.X509Certificates.Asn1.ReasonFlagsAsn" implicitTag="1" optional="true" />
+  <asn:SequenceOf name="CRLIssuer" implicitTag="2" optional="true">
+    <asn:AsnType typeName="System.Security.Cryptography.Asn1.GeneralNameAsn" />
+  </asn:SequenceOf>
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointAsn.xml.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointAsn.xml.cs
new file mode 100644 (file)
index 0000000..e5f214b
--- /dev/null
@@ -0,0 +1,129 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.X509Certificates.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct DistributionPointAsn
+    {
+        internal System.Security.Cryptography.X509Certificates.Asn1.DistributionPointNameAsn? DistributionPoint;
+        internal System.Security.Cryptography.X509Certificates.Asn1.ReasonFlagsAsn? Reasons;
+        internal System.Security.Cryptography.Asn1.GeneralNameAsn[] CRLIssuer;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+
+            if (DistributionPoint.HasValue)
+            {
+                writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+                DistributionPoint.Value.Encode(writer);
+                writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+            }
+
+
+            if (Reasons.HasValue)
+            {
+                writer.WriteNamedBitList(new Asn1Tag(TagClass.ContextSpecific, 1), Reasons.Value);
+            }
+
+
+            if (CRLIssuer != null)
+            {
+
+                writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
+                for (int i = 0; i < CRLIssuer.Length; i++)
+                {
+                    CRLIssuer[i].Encode(writer); 
+                }
+                writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
+
+            }
+
+            writer.PopSequence(tag);
+        }
+
+        internal static DistributionPointAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static DistributionPointAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out DistributionPointAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out DistributionPointAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out DistributionPointAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnReader explicitReader;
+            AsnReader collectionReader;
+            
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
+            {
+                explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+                System.Security.Cryptography.X509Certificates.Asn1.DistributionPointNameAsn tmpDistributionPoint;
+                System.Security.Cryptography.X509Certificates.Asn1.DistributionPointNameAsn.Decode(explicitReader, out tmpDistributionPoint);
+                decoded.DistributionPoint = tmpDistributionPoint;
+
+                explicitReader.ThrowIfNotEmpty();
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
+            {
+                decoded.Reasons = sequenceReader.GetNamedBitListValue<System.Security.Cryptography.X509Certificates.Asn1.ReasonFlagsAsn>(new Asn1Tag(TagClass.ContextSpecific, 1));
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2)))
+            {
+
+                // Decode SEQUENCE OF for CRLIssuer
+                {
+                    collectionReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
+                    var tmpList = new List<System.Security.Cryptography.Asn1.GeneralNameAsn>();
+                    System.Security.Cryptography.Asn1.GeneralNameAsn tmpItem;
+
+                    while (collectionReader.HasData)
+                    {
+                        System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(collectionReader, out tmpItem); 
+                        tmpList.Add(tmpItem);
+                    }
+
+                    decoded.CRLIssuer = tmpList.ToArray();
+                }
+
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointNameAsn.xml b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointNameAsn.xml
new file mode 100644 (file)
index 0000000..24b8cdf
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Choice
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="DistributionPointNameAsn"
+  namespace="System.Security.Cryptography.X509Certificates.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc5280#section-4.2.1.13
+
+    DistributionPointName ::= CHOICE {
+        fullName                [0]     GeneralNames,
+        nameRelativeToCRLIssuer [1]     RelativeDistinguishedName
+    }
+  -->
+  <asn:SequenceOf name="FullName" implicitTag="0">
+    <asn:AsnType typeName="System.Security.Cryptography.Asn1.GeneralNameAsn" />
+  </asn:SequenceOf>
+  <asn:AnyValue name="NameRelativeToCRLIssuer" implicitTag="1" />
+</asn:Choice>
\ No newline at end of file
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointNameAsn.xml.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointNameAsn.xml.cs
new file mode 100644 (file)
index 0000000..68f3875
--- /dev/null
@@ -0,0 +1,125 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.X509Certificates.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct DistributionPointNameAsn
+    {
+        internal System.Security.Cryptography.Asn1.GeneralNameAsn[] FullName;
+        internal ReadOnlyMemory<byte>? NameRelativeToCRLIssuer;
+
+#if DEBUG
+        static DistributionPointNameAsn()
+        {
+            var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
+            Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
+            {
+                if (usedTags.TryGetValue(tag, out string existing))
+                {
+                    throw new InvalidOperationException($"Tag '{tag}' is in use by both '{existing}' and '{fieldName}'");
+                }
+
+                usedTags.Add(tag, fieldName);
+            };
+            
+            ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "FullName");
+            ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 1), "NameRelativeToCRLIssuer");
+        }
+#endif
+
+        internal void Encode(AsnWriter writer)
+        {
+            bool wroteValue = false; 
+            
+            if (FullName != null)
+            {
+                if (wroteValue)
+                    throw new CryptographicException();
+                
+
+                writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+                for (int i = 0; i < FullName.Length; i++)
+                {
+                    FullName[i].Encode(writer); 
+                }
+                writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+
+                wroteValue = true;
+            }
+
+            if (NameRelativeToCRLIssuer.HasValue)
+            {
+                if (wroteValue)
+                    throw new CryptographicException();
+                
+                // Validator for tag constraint for NameRelativeToCRLIssuer
+                {
+                    if (!Asn1Tag.TryParse(NameRelativeToCRLIssuer.Value.Span, out Asn1Tag validateTag, out _) ||
+                        !validateTag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
+                    {
+                        throw new CryptographicException();
+                    }
+                }
+
+                writer.WriteEncodedValue(NameRelativeToCRLIssuer.Value);
+                wroteValue = true;
+            }
+
+            if (!wroteValue)
+            {
+                throw new CryptographicException();
+            }
+        }
+
+        internal static DistributionPointNameAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, out DistributionPointNameAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out DistributionPointNameAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            Asn1Tag tag = reader.PeekTag();
+            AsnReader collectionReader;
+            
+            if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
+            {
+
+                // Decode SEQUENCE OF for FullName
+                {
+                    collectionReader = reader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
+                    var tmpList = new List<System.Security.Cryptography.Asn1.GeneralNameAsn>();
+                    System.Security.Cryptography.Asn1.GeneralNameAsn tmpItem;
+
+                    while (collectionReader.HasData)
+                    {
+                        System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(collectionReader, out tmpItem); 
+                        tmpList.Add(tmpItem);
+                    }
+
+                    decoded.FullName = tmpList.ToArray();
+                }
+
+            }
+            else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
+            {
+                decoded.NameRelativeToCRLIssuer = reader.GetEncodedValue();
+            }
+            else
+            {
+                throw new CryptographicException();
+            }
+        }
+    }
+}
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyConstraintsAsn.xml b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyConstraintsAsn.xml
new file mode 100644 (file)
index 0000000..dcc5ac1
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="PolicyConstraintsAsn"
+  namespace="System.Security.Cryptography.X509Certificates.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc5280#section-4.2.1.11
+
+    PolicyConstraints ::= SEQUENCE {
+        requireExplicitPolicy           [0] SkipCerts OPTIONAL,
+        inhibitPolicyMapping            [1] SkipCerts OPTIONAL
+    }
+
+    SkipCerts ::= INTEGER (0..MAX)
+  -->
+  <asn:Integer name="RequireExplicitPolicyDepth" implicitTag="0" backingType="int" optional="true" />
+  <asn:Integer name="InhibitMappingDepth" implicitTag="1" backingType="int" optional="true" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyConstraintsAsn.xml.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyConstraintsAsn.xml.cs
new file mode 100644 (file)
index 0000000..e33c3d8
--- /dev/null
@@ -0,0 +1,102 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.X509Certificates.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct PolicyConstraintsAsn
+    {
+        internal int? RequireExplicitPolicyDepth;
+        internal int? InhibitMappingDepth;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+
+            if (RequireExplicitPolicyDepth.HasValue)
+            {
+                writer.WriteInteger(new Asn1Tag(TagClass.ContextSpecific, 0), RequireExplicitPolicyDepth.Value);
+            }
+
+
+            if (InhibitMappingDepth.HasValue)
+            {
+                writer.WriteInteger(new Asn1Tag(TagClass.ContextSpecific, 1), InhibitMappingDepth.Value);
+            }
+
+            writer.PopSequence(tag);
+        }
+
+        internal static PolicyConstraintsAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static PolicyConstraintsAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out PolicyConstraintsAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out PolicyConstraintsAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PolicyConstraintsAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
+            {
+
+                if (sequenceReader.TryReadInt32(new Asn1Tag(TagClass.ContextSpecific, 0), out int tmpRequireExplicitPolicyDepth))
+                {
+                    decoded.RequireExplicitPolicyDepth = tmpRequireExplicitPolicyDepth;
+                }
+                else
+                {
+                    sequenceReader.ThrowIfNotEmpty();
+                }
+
+            }
+
+
+            if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
+            {
+
+                if (sequenceReader.TryReadInt32(new Asn1Tag(TagClass.ContextSpecific, 1), out int tmpInhibitMappingDepth))
+                {
+                    decoded.InhibitMappingDepth = tmpInhibitMappingDepth;
+                }
+                else
+                {
+                    sequenceReader.ThrowIfNotEmpty();
+                }
+
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyInformationAsn.xml b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyInformationAsn.xml
new file mode 100644 (file)
index 0000000..02e93e2
--- /dev/null
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<asn:Sequence
+  xmlns:asn="http://schemas.dot.net/asnxml/201808/"
+  name="PolicyInformationAsn"
+  namespace="System.Security.Cryptography.X509Certificates.Asn1">
+
+  <!--
+    https://tools.ietf.org/html/rfc5280#section-4.2.1.4
+
+    PolicyInformation ::= SEQUENCE {
+        policyIdentifier   CertPolicyId,
+        policyQualifiers   SEQUENCE SIZE (1..MAX) OF
+                           PolicyQualifierInfo OPTIONAL
+    }
+
+    CertPolicyId ::= OBJECT IDENTIFIER
+
+    PolicyQualifierInfo ::= SEQUENCE {
+        policyQualifierId  PolicyQualifierId,
+        qualifier          ANY DEFINED BY policyQualifierId
+    }
+  -->
+  <asn:ObjectIdentifier name="PolicyIdentifier" backingType="string" />
+  <asn:AnyValue name="PolicyQualifiers" optional="true" />
+</asn:Sequence>
\ No newline at end of file
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyInformationAsn.xml.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyInformationAsn.xml.cs
new file mode 100644 (file)
index 0000000..01c07b1
--- /dev/null
@@ -0,0 +1,74 @@
+using System;
+using System.Runtime.InteropServices;
+using System.Security.Cryptography;
+using System.Security.Cryptography.Asn1;
+
+namespace System.Security.Cryptography.X509Certificates.Asn1
+{
+    [StructLayout(LayoutKind.Sequential)]
+    internal partial struct PolicyInformationAsn
+    {
+        internal string PolicyIdentifier;
+        internal ReadOnlyMemory<byte>? PolicyQualifiers;
+      
+        internal void Encode(AsnWriter writer)
+        {
+            Encode(writer, Asn1Tag.Sequence);
+        }
+    
+        internal void Encode(AsnWriter writer, Asn1Tag tag)
+        {
+            writer.PushSequence(tag);
+            
+            writer.WriteObjectIdentifier(PolicyIdentifier);
+
+            if (PolicyQualifiers.HasValue)
+            {
+                writer.WriteEncodedValue(PolicyQualifiers.Value);
+            }
+
+            writer.PopSequence(tag);
+        }
+
+        internal static PolicyInformationAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            return Decode(Asn1Tag.Sequence, encoded, ruleSet);
+        }
+        
+        internal static PolicyInformationAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
+        {
+            AsnReader reader = new AsnReader(encoded, ruleSet);
+            
+            Decode(reader, expectedTag, out PolicyInformationAsn decoded);
+            reader.ThrowIfNotEmpty();
+            return decoded;
+        }
+
+        internal static void Decode(AsnReader reader, out PolicyInformationAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            Decode(reader, Asn1Tag.Sequence, out decoded);
+        }
+
+        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PolicyInformationAsn decoded)
+        {
+            if (reader == null)
+                throw new ArgumentNullException(nameof(reader));
+
+            decoded = default;
+            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
+            
+            decoded.PolicyIdentifier = sequenceReader.ReadObjectIdentifierAsString();
+
+            if (sequenceReader.HasData)
+            {
+                decoded.PolicyQualifiers = sequenceReader.GetEncodedValue();
+            }
+
+
+            sequenceReader.ThrowIfNotEmpty();
+        }
+    }
+}
diff --git a/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/ReasonFlagsAsn.cs b/src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/ReasonFlagsAsn.cs
new file mode 100644 (file)
index 0000000..cea2fb6
--- /dev/null
@@ -0,0 +1,33 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+namespace System.Security.Cryptography.X509Certificates.Asn1
+{
+    // https://tools.ietf.org/html/rfc5280#section-4.2.1.13
+    //
+    // ReasonFlags ::= BIT STRING {
+    //     unused                  (0),
+    //     keyCompromise           (1),
+    //     cACompromise            (2),
+    //     affiliationChanged      (3),
+    //     superseded              (4),
+    //     cessationOfOperation    (5),
+    //     certificateHold         (6),
+    //     privilegeWithdrawn      (7),
+    //     aACompromise            (8)
+    // }
+    [Flags]
+    internal enum ReasonFlagsAsn
+    {
+        Unused = 1 << 0,
+        KeyCompromise = 1 << 1,
+        CACompromise = 1 << 2,
+        AffiliationChanged = 1 << 3,
+        Superseded = 1 << 4,
+        CessationOfOperation = 1 << 5,
+        CertificateHold = 1 << 6,
+        PrivilegeWithdrawn = 1 << 7,
+        AACompromise = 1 << 8,
+    }
+}
index b4fa6b2..f0ff9c5 100644 (file)
@@ -584,7 +584,7 @@ namespace System.Security.Cryptography.X509Certificates
                             SR.Format(SR.Cryptography_CertReq_DuplicateExtension, extension.Oid.Value));
                     }
 
-                    extensionAsns.Add(new X509ExtensionAsn(extension, false));
+                    extensionAsns.Add(new X509ExtensionAsn(extension));
                 }
 
                 tbsCertificate.Extensions = extensionAsns.ToArray();