Split AsnReader into a class and a ref struct (AsnValueReader)
authorJeremy Barton <jbarton@microsoft.com>
Wed, 22 Jan 2020 16:16:39 +0000 (08:16 -0800)
committerGitHub <noreply@github.com>
Wed, 22 Jan 2020 16:16:39 +0000 (08:16 -0800)
Largely, the intent of this change was to reduce the number of temporary readers required for deeply structured payloads (`ReadSequence` returns a new reader), while still maintaining the better usability of the class; and, frankly, to understand what the impact of splitting functionality into "bare metal" and "more usable" pieces was.

```
foreach (file in AsnReader.*)
{
    Copy/paste the entirety of the `partial class AsnReader`;
    Change the top version to say ref partial struct AsnValueReader;
    Replace all AsnReader calls in the top version to say AsnValueReader.
    Replace all ReadOnlyMemory in the top portion with ReadOnlySpan;
    Remove ArraySegment overloads from the top portion (when present);
    Rewrite the bottom portion to open a ref reader at the state the memory is tracking and defer work into the ref reader;
    Run all the existing tests to ensure that nothing broke in that piece;
}
```

Once that was done, I changed the asn.xslt to generate all of the decoding in terms of AsnValueReader.  This didn't change field generation from ReadOnlyMemory to ReadOnlySpan (and the types from struct to ref struct)--a change that could be done later--but instead added a new ReadOnlyMemory input parameter so it can use Overlaps to slice the memory as appropriate (with a fallback of ToArray()).

While I was editing asn.xslt I fixed probably all of the whitespace errors it generated.  I still left the "stylecop, have no opinion about whitespace" pragma since the generator isn't run as part of most people's (or the official) builds.  This also turns on the nullability checks in all of the generated structs.

114 files changed:
src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/CurveAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/DigestInfoAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/DirectoryStringAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/DssParms.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/ECDomainParameters.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/EdiPartyNameAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/GeneralNameAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/OaepParamsAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/OtherNameAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs12/CertBagAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs12/MacData.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs12/PfxAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs12/SafeBagAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs7/ContentInfoAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs7/EncryptedContentInfoAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs7/EncryptedDataAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/Rc2CbcParameters.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1/asn.xslt
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.BitString.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.Boolean.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.Enumerated.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.GeneralizedTime.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.Integer.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.NamedBitList.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.Null.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.OctetString.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.Oid.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.Sequence.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.SetOf.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.Text.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.UtcTime.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/AsnReader.cs
src/libraries/Common/src/System/Security/Cryptography/Asn1Reader/SetOfValueComparer.cs
src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs
src/libraries/System.Security.Cryptography.Encoding/src/Internal/Cryptography/AsnFormatter.OSX.cs
src/libraries/System.Security.Cryptography.Encoding/tests/Asn1/Reader/PeekTests.cs
src/libraries/System.Security.Cryptography.Encoding/tests/Asn1/Reader/ReadObjectIdentifier.cs
src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Asn.cs
src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/Pal/AnyOS/ManagedPal.Decode.cs
src/libraries/System.Security.Cryptography.Pkcs/src/Internal/Cryptography/PkcsHelpers.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/CadesIssuerSerial.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/CertificateChoiceAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EncapsulatedContentInfoAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EnvelopedDataAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EssCertId.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EssCertIdV2.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/IssuerAndSerialNumberAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientIdentifierAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientInfoAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyTransRecipientInfoAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorIdentifierOrKeyAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorInfoAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorPublicKeyAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OtherKeyAttributeAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/PkiStatusInfo.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/PolicyInformation.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/PolicyQualifierInfo.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientEncryptedKeyAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientIdentifierAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientInfoAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientKeyIdentifier.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161Accuracy.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampReq.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TimeStampResp.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SecretBagAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SignedAttributesSet.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SignedDataAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SignerIdentifierAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SignerInfoAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SigningCertificateAsn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SigningCertificateV2Asn.xml.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Pkcs12Info.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Pkcs12SafeContents.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Pkcs8PrivateKeyInfo.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampRequest.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Rfc3161TimestampToken.cs
src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/SignedCms.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/OpenSslX509ChainProcessor.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/Internal/Cryptography/Pal.Unix/UnixPkcs12Reader.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/AccessDescriptionAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/BasicConstraintsAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificateAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificatePolicyMappingAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificateTemplateAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificationRequestAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/CertificationRequestInfoAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointNameAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyConstraintsAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/PolicyInformationAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/TbsCertificateAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/TimeAsn.xml.cs
src/libraries/System.Security.Cryptography.X509Certificates/src/System/Security/Cryptography/X509Certificates/Asn1/ValidityAsn.xml.cs

index a28aeda..ccea20e 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1
     {
         internal Oid Algorithm;
         internal ReadOnlyMemory<byte>? Parameters;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteObjectIdentifier(Algorithm);
 
             if (Parameters.HasValue)
@@ -39,37 +39,35 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static AlgorithmIdentifierAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out AlgorithmIdentifierAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out AlgorithmIdentifierAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out AlgorithmIdentifierAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out AlgorithmIdentifierAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out AlgorithmIdentifierAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out AlgorithmIdentifierAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.Algorithm = sequenceReader.ReadObjectIdentifier();
 
             if (sequenceReader.HasData)
             {
-                decoded.Parameters = sequenceReader.ReadEncodedValue();
+                tmpSpan = sequenceReader.ReadEncodedValue();
+                decoded.Parameters = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
 
 
index e7bb297..47e0d86 100644 (file)
@@ -16,22 +16,22 @@ namespace System.Security.Cryptography.Asn1
     {
         internal Oid AttrType;
         internal ReadOnlyMemory<byte>[] AttrValues;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteObjectIdentifier(AttrType);
 
             writer.PushSetOf();
             for (int i = 0; i < AttrValues.Length; i++)
             {
-                writer.WriteEncodedValue(AttrValues[i].Span); 
+                writer.WriteEncodedValue(AttrValues[i].Span);
             }
             writer.PopSetOf();
 
@@ -42,33 +42,30 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static AttributeAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out AttributeAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out AttributeAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out AttributeAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out AttributeAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out AttributeAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out AttributeAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.AttrType = sequenceReader.ReadObjectIdentifier();
 
             // Decode SEQUENCE OF for AttrValues
@@ -79,7 +76,8 @@ namespace System.Security.Cryptography.Asn1
 
                 while (collectionReader.HasData)
                 {
-                    tmpItem = collectionReader.ReadEncodedValue(); 
+                    tmpSpan = collectionReader.ReadEncodedValue();
+                    tmpItem = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                     tmpList.Add(tmpItem);
                 }
 
index ec05ede..83f2507 100644 (file)
@@ -16,16 +16,16 @@ namespace System.Security.Cryptography.Asn1
         internal ReadOnlyMemory<byte> A;
         internal ReadOnlyMemory<byte> B;
         internal ReadOnlyMemory<byte>? Seed;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteOctetString(A.Span);
             writer.WriteOctetString(B.Span);
 
@@ -41,36 +41,33 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static CurveAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out CurveAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out CurveAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out CurveAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out CurveAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CurveAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out CurveAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpA))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.A = tmpA;
+                decoded.A = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
@@ -78,9 +75,9 @@ namespace System.Security.Cryptography.Asn1
             }
 
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpB))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.B = tmpB;
+                decoded.B = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
@@ -91,9 +88,9 @@ namespace System.Security.Cryptography.Asn1
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.PrimitiveBitString))
             {
 
-                if (sequenceReader.TryReadPrimitiveBitStringValue(out _, out ReadOnlyMemory<byte> tmpSeed))
+                if (sequenceReader.TryReadPrimitiveBitStringValue(out _, out tmpSpan))
                 {
-                    decoded.Seed = tmpSeed;
+                    decoded.Seed = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 }
                 else
                 {
index 20b4d46..64c0b1b 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1
     {
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn DigestAlgorithm;
         internal ReadOnlyMemory<byte> Digest;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             DigestAlgorithm.Encode(writer);
             writer.WriteOctetString(Digest.Span);
             writer.PopSequence(tag);
@@ -34,37 +34,34 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static DigestInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out DigestInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out DigestInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out DigestInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out DigestInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out DigestInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out DigestInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.DigestAlgorithm);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.DigestAlgorithm);
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpDigest))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.Digest = tmpDigest;
+                decoded.Digest = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index 577ade2..7310045 100644 (file)
@@ -33,7 +33,7 @@ namespace System.Security.Cryptography.Asn1
 
                 usedTags.Add(tag, fieldName);
             };
-            
+
             ensureUniqueTag(new Asn1Tag(UniversalTagNumber.T61String), "TeletexString");
             ensureUniqueTag(new Asn1Tag(UniversalTagNumber.PrintableString), "PrintableString");
             ensureUniqueTag(new Asn1Tag((UniversalTagNumber)28), "UniversalString");
@@ -44,13 +44,13 @@ namespace System.Security.Cryptography.Asn1
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            bool wroteValue = false;
+
             if (TeletexString != null)
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteCharacterString(UniversalTagNumber.T61String, TeletexString);
                 wroteValue = true;
             }
@@ -59,7 +59,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteCharacterString(UniversalTagNumber.PrintableString, PrintableString);
                 wroteValue = true;
             }
@@ -68,7 +68,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 // Validator for tag constraint for UniversalString
                 {
                     if (!Asn1Tag.TryDecode(UniversalString.Value.Span, out Asn1Tag validateTag, out _) ||
@@ -86,7 +86,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteCharacterString(UniversalTagNumber.UTF8String, Utf8String);
                 wroteValue = true;
             }
@@ -95,7 +95,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteCharacterString(UniversalTagNumber.BMPString, BmpString);
                 wroteValue = true;
             }
@@ -108,21 +108,21 @@ namespace System.Security.Cryptography.Asn1
 
         internal static DirectoryStringAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out DirectoryStringAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out DirectoryStringAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out DirectoryStringAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out DirectoryStringAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             if (tag.HasSameClassAndValue(new Asn1Tag(UniversalTagNumber.T61String)))
             {
                 decoded.TeletexString = reader.ReadCharacterString(UniversalTagNumber.T61String);
@@ -133,7 +133,8 @@ namespace System.Security.Cryptography.Asn1
             }
             else if (tag.HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)28)))
             {
-                decoded.UniversalString = reader.ReadEncodedValue();
+                tmpSpan = reader.ReadEncodedValue();
+                decoded.UniversalString = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else if (tag.HasSameClassAndValue(new Asn1Tag(UniversalTagNumber.UTF8String)))
             {
index bc37937..a45f9f5 100644 (file)
@@ -16,16 +16,16 @@ namespace System.Security.Cryptography.Asn1
         internal System.Numerics.BigInteger P;
         internal System.Numerics.BigInteger Q;
         internal System.Numerics.BigInteger G;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(P);
             writer.WriteInteger(Q);
             writer.WriteInteger(G);
@@ -36,32 +36,26 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static DssParms Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out DssParms decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out DssParms decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out DssParms decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out DssParms decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out DssParms decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out DssParms decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+
             decoded.P = sequenceReader.ReadInteger();
             decoded.Q = sequenceReader.ReadInteger();
             decoded.G = sequenceReader.ReadInteger();
index b0a8212..c762729 100644 (file)
@@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Asn1;
 
+#nullable enable
 namespace System.Security.Cryptography.Asn1
 {
     [StructLayout(LayoutKind.Sequential)]
@@ -22,14 +23,14 @@ namespace System.Security.Cryptography.Asn1
             var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
             Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
             {
-                if (usedTags.TryGetValue(tag, out string existing))
+                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(Asn1Tag.Sequence, "Specified");
             ensureUniqueTag(Asn1Tag.ObjectIdentifier, "Named");
         }
@@ -37,13 +38,13 @@ namespace System.Security.Cryptography.Asn1
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            bool wroteValue = false;
+
             if (Specified.HasValue)
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 Specified.Value.Encode(writer);
                 wroteValue = true;
             }
@@ -52,7 +53,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteObjectIdentifier(Named);
                 wroteValue = true;
             }
@@ -65,25 +66,22 @@ namespace System.Security.Cryptography.Asn1
 
         internal static ECDomainParameters Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out ECDomainParameters decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out ECDomainParameters decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out ECDomainParameters decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out ECDomainParameters decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            
+
             if (tag.HasSameClassAndValue(Asn1Tag.Sequence))
             {
                 System.Security.Cryptography.Asn1.SpecifiedECDomain tmpSpecified;
-                System.Security.Cryptography.Asn1.SpecifiedECDomain.Decode(reader, out tmpSpecified);
+                System.Security.Cryptography.Asn1.SpecifiedECDomain.Decode(ref reader, rebind, out tmpSpecified);
                 decoded.Specified = tmpSpecified;
 
             }
index 4c60457..bb43eed 100644 (file)
@@ -17,16 +17,16 @@ namespace System.Security.Cryptography.Asn1
         internal ReadOnlyMemory<byte> PrivateKey;
         internal System.Security.Cryptography.Asn1.ECDomainParameters? Parameters;
         internal ReadOnlyMemory<byte>? PublicKey;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Version);
             writer.WriteOctetString(PrivateKey.Span);
 
@@ -52,33 +52,30 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static ECPrivateKey Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out ECPrivateKey decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out ECPrivateKey decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out ECPrivateKey decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out ECPrivateKey decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out ECPrivateKey decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out ECPrivateKey decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (!sequenceReader.TryReadUInt8(out decoded.Version))
             {
@@ -86,9 +83,9 @@ namespace System.Security.Cryptography.Asn1
             }
 
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpPrivateKey))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.PrivateKey = tmpPrivateKey;
+                decoded.PrivateKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
@@ -100,7 +97,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                 System.Security.Cryptography.Asn1.ECDomainParameters tmpParameters;
-                System.Security.Cryptography.Asn1.ECDomainParameters.Decode(explicitReader, out tmpParameters);
+                System.Security.Cryptography.Asn1.ECDomainParameters.Decode(ref explicitReader, rebind, out tmpParameters);
                 decoded.Parameters = tmpParameters;
 
                 explicitReader.ThrowIfNotEmpty();
@@ -111,9 +108,9 @@ namespace System.Security.Cryptography.Asn1
             {
                 explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
 
-                if (explicitReader.TryReadPrimitiveBitStringValue(out _, out ReadOnlyMemory<byte> tmpPublicKey))
+                if (explicitReader.TryReadPrimitiveBitStringValue(out _, out tmpSpan))
                 {
-                    decoded.PublicKey = tmpPublicKey;
+                    decoded.PublicKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 }
                 else
                 {
index 8ecae76..b1b5c40 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1
     {
         internal System.Security.Cryptography.Asn1.DirectoryStringAsn? NameAssigner;
         internal System.Security.Cryptography.Asn1.DirectoryStringAsn PartyName;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
 
             if (NameAssigner.HasValue)
             {
@@ -43,39 +43,33 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static EdiPartyNameAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out EdiPartyNameAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out EdiPartyNameAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out EdiPartyNameAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out EdiPartyNameAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EdiPartyNameAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out EdiPartyNameAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
                 explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                 System.Security.Cryptography.Asn1.DirectoryStringAsn tmpNameAssigner;
-                System.Security.Cryptography.Asn1.DirectoryStringAsn.Decode(explicitReader, out tmpNameAssigner);
+                System.Security.Cryptography.Asn1.DirectoryStringAsn.Decode(ref explicitReader, rebind, out tmpNameAssigner);
                 decoded.NameAssigner = tmpNameAssigner;
 
                 explicitReader.ThrowIfNotEmpty();
@@ -83,7 +77,7 @@ namespace System.Security.Cryptography.Asn1
 
 
             explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
-            System.Security.Cryptography.Asn1.DirectoryStringAsn.Decode(explicitReader, out decoded.PartyName);
+            System.Security.Cryptography.Asn1.DirectoryStringAsn.Decode(ref explicitReader, rebind, out decoded.PartyName);
             explicitReader.ThrowIfNotEmpty();
 
 
index 106164b..5e1dbe8 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1
     {
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn EncryptionAlgorithm;
         internal ReadOnlyMemory<byte> EncryptedData;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             EncryptionAlgorithm.Encode(writer);
             writer.WriteOctetString(EncryptedData.Span);
             writer.PopSequence(tag);
@@ -34,37 +34,34 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static EncryptedPrivateKeyInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out EncryptedPrivateKeyInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out EncryptedPrivateKeyInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out EncryptedPrivateKeyInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out EncryptedPrivateKeyInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EncryptedPrivateKeyInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out EncryptedPrivateKeyInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.EncryptionAlgorithm);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.EncryptionAlgorithm);
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpEncryptedData))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.EncryptedData = tmpEncryptedData;
+                decoded.EncryptedData = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index ce3d2e2..b95903d 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1
     {
         internal string FieldType;
         internal ReadOnlyMemory<byte> Parameters;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteObjectIdentifier(FieldType);
             writer.WriteEncodedValue(Parameters.Span);
             writer.PopSequence(tag);
@@ -34,34 +34,32 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static FieldID Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out FieldID decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out FieldID decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out FieldID decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out FieldID decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out FieldID decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out FieldID decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.FieldType = sequenceReader.ReadObjectIdentifierAsString();
-            decoded.Parameters = sequenceReader.ReadEncodedValue();
+            tmpSpan = sequenceReader.ReadEncodedValue();
+            decoded.Parameters = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
 
             sequenceReader.ThrowIfNotEmpty();
         }
index 4702788..dfd3116 100644 (file)
@@ -37,7 +37,7 @@ namespace System.Security.Cryptography.Asn1
 
                 usedTags.Add(tag, fieldName);
             };
-            
+
             ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "OtherName");
             ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 1), "Rfc822Name");
             ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 2), "DnsName");
@@ -52,13 +52,13 @@ namespace System.Security.Cryptography.Asn1
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            bool wroteValue = false;
+
             if (OtherName.HasValue)
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 OtherName.Value.Encode(writer, new Asn1Tag(TagClass.ContextSpecific, 0));
                 wroteValue = true;
             }
@@ -67,7 +67,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteCharacterString(new Asn1Tag(TagClass.ContextSpecific, 1), UniversalTagNumber.IA5String, Rfc822Name);
                 wroteValue = true;
             }
@@ -76,7 +76,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteCharacterString(new Asn1Tag(TagClass.ContextSpecific, 2), UniversalTagNumber.IA5String, DnsName);
                 wroteValue = true;
             }
@@ -85,7 +85,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 // Validator for tag constraint for X400Address
                 {
                     if (!Asn1Tag.TryDecode(X400Address.Value.Span, out Asn1Tag validateTag, out _) ||
@@ -103,7 +103,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 4));
                 writer.WriteEncodedValue(DirectoryName.Value.Span);
                 writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 4));
@@ -114,7 +114,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 EdiPartyName.Value.Encode(writer, new Asn1Tag(TagClass.ContextSpecific, 5));
                 wroteValue = true;
             }
@@ -123,7 +123,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteCharacterString(new Asn1Tag(TagClass.ContextSpecific, 6), UniversalTagNumber.IA5String, Uri);
                 wroteValue = true;
             }
@@ -132,7 +132,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteOctetString(new Asn1Tag(TagClass.ContextSpecific, 7), IPAddress.Value.Span);
                 wroteValue = true;
             }
@@ -141,7 +141,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteObjectIdentifier(new Asn1Tag(TagClass.ContextSpecific, 8), RegisteredId);
                 wroteValue = true;
             }
@@ -154,26 +154,26 @@ namespace System.Security.Cryptography.Asn1
 
         internal static GeneralNameAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out GeneralNameAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out GeneralNameAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out GeneralNameAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out GeneralNameAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            AsnReader explicitReader;
-            
+            AsnValueReader explicitReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
                 System.Security.Cryptography.Asn1.OtherNameAsn tmpOtherName;
-                System.Security.Cryptography.Asn1.OtherNameAsn.Decode(reader, new Asn1Tag(TagClass.ContextSpecific, 0), out tmpOtherName);
+                System.Security.Cryptography.Asn1.OtherNameAsn.Decode(ref reader, new Asn1Tag(TagClass.ContextSpecific, 0), rebind, out tmpOtherName);
                 decoded.OtherName = tmpOtherName;
 
             }
@@ -187,18 +187,20 @@ namespace System.Security.Cryptography.Asn1
             }
             else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 3)))
             {
-                decoded.X400Address = reader.ReadEncodedValue();
+                tmpSpan = reader.ReadEncodedValue();
+                decoded.X400Address = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 4)))
             {
                 explicitReader = reader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 4));
-                decoded.DirectoryName = explicitReader.ReadEncodedValue();
+                tmpSpan = explicitReader.ReadEncodedValue();
+                decoded.DirectoryName = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 explicitReader.ThrowIfNotEmpty();
             }
             else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 5)))
             {
                 System.Security.Cryptography.Asn1.EdiPartyNameAsn tmpEdiPartyName;
-                System.Security.Cryptography.Asn1.EdiPartyNameAsn.Decode(reader, new Asn1Tag(TagClass.ContextSpecific, 5), out tmpEdiPartyName);
+                System.Security.Cryptography.Asn1.EdiPartyNameAsn.Decode(ref reader, new Asn1Tag(TagClass.ContextSpecific, 5), rebind, out tmpEdiPartyName);
                 decoded.EdiPartyName = tmpEdiPartyName;
 
             }
@@ -209,9 +211,9 @@ namespace System.Security.Cryptography.Asn1
             else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 7)))
             {
 
-                if (reader.TryReadPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 7), out ReadOnlyMemory<byte> tmpIPAddress))
+                if (reader.TryReadPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 7), out tmpSpan))
                 {
-                    decoded.IPAddress = tmpIPAddress;
+                    decoded.IPAddress = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 }
                 else
                 {
index 6d79915..e1bc57c 100644 (file)
@@ -14,44 +14,45 @@ namespace System.Security.Cryptography.Asn1
     internal partial struct OaepParamsAsn
     {
         private static readonly byte[] s_defaultHashFunc = { 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 };
-  
+
         private static readonly byte[] s_defaultMaskGenFunc = { 0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 };
-  
+
         private static readonly byte[] s_defaultPSourceFunc = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x09, 0x04, 0x00 };
-  
+
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashFunc;
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenFunc;
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn PSourceFunc;
-      
+
 #if DEBUG
         static OaepParamsAsn()
         {
             OaepParamsAsn decoded = default;
-            AsnReader reader;
+            ReadOnlyMemory<byte> rebind = default;
+            AsnValueReader reader;
 
-            reader = new AsnReader(s_defaultHashFunc, AsnEncodingRules.DER);
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.HashFunc);
+            reader = new AsnValueReader(s_defaultHashFunc, AsnEncodingRules.DER);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashFunc);
             reader.ThrowIfNotEmpty();
 
-            reader = new AsnReader(s_defaultMaskGenFunc, AsnEncodingRules.DER);
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.MaskGenFunc);
+            reader = new AsnValueReader(s_defaultMaskGenFunc, AsnEncodingRules.DER);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.MaskGenFunc);
             reader.ThrowIfNotEmpty();
 
-            reader = new AsnReader(s_defaultPSourceFunc, AsnEncodingRules.DER);
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.PSourceFunc);
+            reader = new AsnValueReader(s_defaultPSourceFunc, AsnEncodingRules.DER);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.PSourceFunc);
             reader.ThrowIfNotEmpty();
         }
 #endif
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
 
             // DEFAULT value handler for HashFunc.
             {
@@ -63,7 +64,7 @@ namespace System.Security.Cryptography.Asn1
                     if (!encoded.SequenceEqual(s_defaultHashFunc))
                     {
                         writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                         writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                     }
                 }
@@ -80,7 +81,7 @@ namespace System.Security.Cryptography.Asn1
                     if (!encoded.SequenceEqual(s_defaultMaskGenFunc))
                     {
                         writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                         writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
                     }
                 }
@@ -97,7 +98,7 @@ namespace System.Security.Cryptography.Asn1
                     if (!encoded.SequenceEqual(s_defaultPSourceFunc))
                     {
                         writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                         writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
                     }
                 }
@@ -110,71 +111,65 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static OaepParamsAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out OaepParamsAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out OaepParamsAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out OaepParamsAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out OaepParamsAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out OaepParamsAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out OaepParamsAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            AsnReader defaultReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            AsnValueReader defaultReader;
+
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
                 explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(explicitReader, out decoded.HashFunc);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref explicitReader, rebind, out decoded.HashFunc);
                 explicitReader.ThrowIfNotEmpty();
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultHashFunc, AsnEncodingRules.DER);
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.HashFunc);
+                defaultReader = new AsnValueReader(s_defaultHashFunc, AsnEncodingRules.DER);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.HashFunc);
             }
 
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
             {
                 explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(explicitReader, out decoded.MaskGenFunc);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref explicitReader, rebind, out decoded.MaskGenFunc);
                 explicitReader.ThrowIfNotEmpty();
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultMaskGenFunc, AsnEncodingRules.DER);
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.MaskGenFunc);
+                defaultReader = new AsnValueReader(s_defaultMaskGenFunc, AsnEncodingRules.DER);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.MaskGenFunc);
             }
 
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2)))
             {
                 explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(explicitReader, out decoded.PSourceFunc);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref explicitReader, rebind, out decoded.PSourceFunc);
                 explicitReader.ThrowIfNotEmpty();
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultPSourceFunc, AsnEncodingRules.DER);
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.PSourceFunc);
+                defaultReader = new AsnValueReader(s_defaultPSourceFunc, AsnEncodingRules.DER);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.PSourceFunc);
             }
 
 
index 78ba407..18bf247 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1
     {
         internal string TypeId;
         internal ReadOnlyMemory<byte> Value;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteObjectIdentifier(TypeId);
             writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
             writer.WriteEncodedValue(Value.Span);
@@ -36,37 +36,35 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static OtherNameAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out OtherNameAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out OtherNameAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out OtherNameAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out OtherNameAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out OtherNameAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out OtherNameAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.TypeId = sequenceReader.ReadObjectIdentifierAsString();
 
             explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
-            decoded.Value = explicitReader.ReadEncodedValue();
+            tmpSpan = explicitReader.ReadEncodedValue();
+            decoded.Value = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             explicitReader.ThrowIfNotEmpty();
 
 
index b6eee4e..2544f2b 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1
     {
         internal ReadOnlyMemory<byte> Salt;
         internal int IterationCount;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteOctetString(Salt.Span);
             writer.WriteInteger(IterationCount);
             writer.PopSequence(tag);
@@ -34,36 +34,33 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static PBEParameter Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out PBEParameter decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out PBEParameter decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out PBEParameter decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out PBEParameter decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PBEParameter decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out PBEParameter decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpSalt))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.Salt = tmpSalt;
+                decoded.Salt = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index 1a5be31..2d45e58 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1
     {
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn KeyDerivationFunc;
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn EncryptionScheme;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             KeyDerivationFunc.Encode(writer);
             EncryptionScheme.Encode(writer);
             writer.PopSequence(tag);
@@ -34,34 +34,28 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static PBES2Params Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out PBES2Params decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out PBES2Params decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out PBES2Params decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out PBES2Params decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PBES2Params decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out PBES2Params decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.KeyDerivationFunc);
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.EncryptionScheme);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.KeyDerivationFunc);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.EncryptionScheme);
 
             sequenceReader.ThrowIfNotEmpty();
         }
index 3991e0e..67c2cec 100644 (file)
@@ -14,33 +14,34 @@ namespace System.Security.Cryptography.Asn1
     internal partial struct Pbkdf2Params
     {
         private static readonly byte[] s_defaultPrf = { 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07, 0x05, 0x00 };
-  
+
         internal System.Security.Cryptography.Asn1.Pbkdf2SaltChoice Salt;
         internal int IterationCount;
         internal byte? KeyLength;
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn Prf;
-      
+
 #if DEBUG
         static Pbkdf2Params()
         {
             Pbkdf2Params decoded = default;
-            AsnReader reader;
+            ReadOnlyMemory<byte> rebind = default;
+            AsnValueReader reader;
 
-            reader = new AsnReader(s_defaultPrf, AsnEncodingRules.DER);
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.Prf);
+            reader = new AsnValueReader(s_defaultPrf, AsnEncodingRules.DER);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.Prf);
             reader.ThrowIfNotEmpty();
         }
 #endif
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             Salt.Encode(writer);
             writer.WriteInteger(IterationCount);
 
@@ -49,7 +50,7 @@ namespace System.Security.Cryptography.Asn1
                 writer.WriteInteger(KeyLength.Value);
             }
 
-        
+
             // DEFAULT value handler for Prf.
             {
                 using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
@@ -59,7 +60,7 @@ namespace System.Security.Cryptography.Asn1
 
                     if (!encoded.SequenceEqual(s_defaultPrf))
                     {
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                     }
                 }
             }
@@ -71,34 +72,28 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static Pbkdf2Params Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out Pbkdf2Params decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out Pbkdf2Params decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out Pbkdf2Params decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out Pbkdf2Params decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Pbkdf2Params decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out Pbkdf2Params decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader defaultReader;
-            
-            System.Security.Cryptography.Asn1.Pbkdf2SaltChoice.Decode(sequenceReader, out decoded.Salt);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader defaultReader;
+
+            System.Security.Cryptography.Asn1.Pbkdf2SaltChoice.Decode(ref sequenceReader, rebind, out decoded.Salt);
 
             if (!sequenceReader.TryReadInt32(out decoded.IterationCount))
             {
@@ -123,12 +118,12 @@ namespace System.Security.Cryptography.Asn1
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
             {
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.Prf);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.Prf);
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultPrf, AsnEncodingRules.DER);
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.Prf);
+                defaultReader = new AsnValueReader(s_defaultPrf, AsnEncodingRules.DER);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.Prf);
             }
 
 
index 2c4ca85..14b5449 100644 (file)
@@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Asn1;
 
+#nullable enable
 namespace System.Security.Cryptography.Asn1
 {
     [StructLayout(LayoutKind.Sequential)]
@@ -22,14 +23,14 @@ namespace System.Security.Cryptography.Asn1
             var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
             Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
             {
-                if (usedTags.TryGetValue(tag, out string existing))
+                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(Asn1Tag.PrimitiveOctetString, "Specified");
             ensureUniqueTag(Asn1Tag.Sequence, "OtherSource");
         }
@@ -37,13 +38,13 @@ namespace System.Security.Cryptography.Asn1
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            bool wroteValue = false;
+
             if (Specified.HasValue)
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteOctetString(Specified.Value.Span);
                 wroteValue = true;
             }
@@ -52,7 +53,7 @@ namespace System.Security.Cryptography.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 OtherSource.Value.Encode(writer);
                 wroteValue = true;
             }
@@ -65,27 +66,27 @@ namespace System.Security.Cryptography.Asn1
 
         internal static Pbkdf2SaltChoice Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out Pbkdf2SaltChoice decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out Pbkdf2SaltChoice decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out Pbkdf2SaltChoice decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out Pbkdf2SaltChoice decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             if (tag.HasSameClassAndValue(Asn1Tag.PrimitiveOctetString))
             {
 
-                if (reader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpSpecified))
+                if (reader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
                 {
-                    decoded.Specified = tmpSpecified;
+                    decoded.Specified = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 }
                 else
                 {
@@ -96,7 +97,7 @@ namespace System.Security.Cryptography.Asn1
             else if (tag.HasSameClassAndValue(Asn1Tag.Sequence))
             {
                 System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn tmpOtherSource;
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out tmpOtherSource);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out tmpOtherSource);
                 decoded.OtherSource = tmpOtherSource;
 
             }
index 3373039..fe4ac88 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
     {
         internal string CertId;
         internal ReadOnlyMemory<byte> CertValue;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteObjectIdentifier(CertId);
             writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
             writer.WriteEncodedValue(CertValue.Span);
@@ -36,37 +36,35 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static CertBagAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out CertBagAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out CertBagAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out CertBagAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out CertBagAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CertBagAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out CertBagAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.CertId = sequenceReader.ReadObjectIdentifierAsString();
 
             explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
-            decoded.CertValue = explicitReader.ReadEncodedValue();
+            tmpSpan = explicitReader.ReadEncodedValue();
+            decoded.CertValue = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             explicitReader.ThrowIfNotEmpty();
 
 
index 3c2d465..cf059b7 100644 (file)
@@ -14,18 +14,18 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
     internal partial struct MacData
     {
         private static readonly byte[] s_defaultIterationCount = { 0x02, 0x01, 0x01 };
-  
+
         internal System.Security.Cryptography.Asn1.DigestInfoAsn Mac;
         internal ReadOnlyMemory<byte> MacSalt;
         internal int IterationCount;
-      
+
 #if DEBUG
         static MacData()
         {
             MacData decoded = default;
-            AsnReader reader;
+            AsnValueReader reader;
 
-            reader = new AsnReader(s_defaultIterationCount, AsnEncodingRules.DER);
+            reader = new AsnValueReader(s_defaultIterationCount, AsnEncodingRules.DER);
 
             if (!reader.TryReadInt32(out decoded.IterationCount))
             {
@@ -35,19 +35,19 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
             reader.ThrowIfNotEmpty();
         }
 #endif
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             Mac.Encode(writer);
             writer.WriteOctetString(MacSalt.Span);
-        
+
             // DEFAULT value handler for IterationCount.
             {
                 using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
@@ -57,7 +57,7 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
 
                     if (!encoded.SequenceEqual(s_defaultIterationCount))
                     {
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                     }
                 }
             }
@@ -69,38 +69,35 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static MacData Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out MacData decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out MacData decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out MacData decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out MacData decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out MacData decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out MacData decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader defaultReader;
-            
-            System.Security.Cryptography.Asn1.DigestInfoAsn.Decode(sequenceReader, out decoded.Mac);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader defaultReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
+            System.Security.Cryptography.Asn1.DigestInfoAsn.Decode(ref sequenceReader, rebind, out decoded.Mac);
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpMacSalt))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.MacSalt = tmpMacSalt;
+                decoded.MacSalt = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
@@ -119,7 +116,7 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultIterationCount, AsnEncodingRules.DER);
+                defaultReader = new AsnValueReader(s_defaultIterationCount, AsnEncodingRules.DER);
 
                 if (!defaultReader.TryReadInt32(out decoded.IterationCount))
                 {
index 3ba2fc3..5364bdf 100644 (file)
@@ -16,16 +16,16 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
         internal byte Version;
         internal System.Security.Cryptography.Asn1.Pkcs7.ContentInfoAsn AuthSafe;
         internal System.Security.Cryptography.Asn1.Pkcs12.MacData? MacData;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Version);
             AuthSafe.Encode(writer);
 
@@ -41,44 +41,38 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static PfxAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out PfxAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out PfxAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out PfxAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out PfxAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PfxAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out PfxAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+
 
             if (!sequenceReader.TryReadUInt8(out decoded.Version))
             {
                 sequenceReader.ThrowIfNotEmpty();
             }
 
-            System.Security.Cryptography.Asn1.Pkcs7.ContentInfoAsn.Decode(sequenceReader, out decoded.AuthSafe);
+            System.Security.Cryptography.Asn1.Pkcs7.ContentInfoAsn.Decode(ref sequenceReader, rebind, out decoded.AuthSafe);
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
             {
                 System.Security.Cryptography.Asn1.Pkcs12.MacData tmpMacData;
-                System.Security.Cryptography.Asn1.Pkcs12.MacData.Decode(sequenceReader, out tmpMacData);
+                System.Security.Cryptography.Asn1.Pkcs12.MacData.Decode(ref sequenceReader, rebind, out tmpMacData);
                 decoded.MacData = tmpMacData;
 
             }
index 9bd193c..e961640 100644 (file)
@@ -17,16 +17,16 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
         internal string BagId;
         internal ReadOnlyMemory<byte> BagValue;
         internal System.Security.Cryptography.Asn1.AttributeAsn[] BagAttributes;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteObjectIdentifier(BagId);
             writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
             writer.WriteEncodedValue(BagValue.Span);
@@ -38,7 +38,7 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
                 writer.PushSetOf();
                 for (int i = 0; i < BagAttributes.Length; i++)
                 {
-                    BagAttributes[i].Encode(writer); 
+                    BagAttributes[i].Encode(writer);
                 }
                 writer.PopSetOf();
 
@@ -51,38 +51,36 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static SafeBagAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out SafeBagAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out SafeBagAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out SafeBagAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out SafeBagAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SafeBagAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out SafeBagAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.BagId = sequenceReader.ReadObjectIdentifierAsString();
 
             explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
-            decoded.BagValue = explicitReader.ReadEncodedValue();
+            tmpSpan = explicitReader.ReadEncodedValue();
+            decoded.BagValue = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             explicitReader.ThrowIfNotEmpty();
 
 
@@ -97,7 +95,7 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index 3a8474a..d7ef164 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1.Pkcs7
     {
         internal string ContentType;
         internal ReadOnlyMemory<byte> Content;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteObjectIdentifier(ContentType);
             writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
             writer.WriteEncodedValue(Content.Span);
@@ -36,37 +36,35 @@ namespace System.Security.Cryptography.Asn1.Pkcs7
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static ContentInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out ContentInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out ContentInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out ContentInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out ContentInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out ContentInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out ContentInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.ContentType = sequenceReader.ReadObjectIdentifierAsString();
 
             explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
-            decoded.Content = explicitReader.ReadEncodedValue();
+            tmpSpan = explicitReader.ReadEncodedValue();
+            decoded.Content = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             explicitReader.ThrowIfNotEmpty();
 
 
index 963778f..b915bea 100644 (file)
@@ -16,16 +16,16 @@ namespace System.Security.Cryptography.Asn1.Pkcs7
         internal string ContentType;
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn ContentEncryptionAlgorithm;
         internal ReadOnlyMemory<byte>? EncryptedContent;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteObjectIdentifier(ContentType);
             ContentEncryptionAlgorithm.Encode(writer);
 
@@ -41,41 +41,38 @@ namespace System.Security.Cryptography.Asn1.Pkcs7
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static EncryptedContentInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out EncryptedContentInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out EncryptedContentInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out EncryptedContentInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out EncryptedContentInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EncryptedContentInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out EncryptedContentInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.ContentType = sequenceReader.ReadObjectIdentifierAsString();
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.ContentEncryptionAlgorithm);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.ContentEncryptionAlgorithm);
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
 
-                if (sequenceReader.TryReadPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 0), out ReadOnlyMemory<byte> tmpEncryptedContent))
+                if (sequenceReader.TryReadPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 0), out tmpSpan))
                 {
-                    decoded.EncryptedContent = tmpEncryptedContent;
+                    decoded.EncryptedContent = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 }
                 else
                 {
index 1186c71..8938c54 100644 (file)
@@ -17,16 +17,16 @@ namespace System.Security.Cryptography.Asn1.Pkcs7
         internal int Version;
         internal System.Security.Cryptography.Asn1.Pkcs7.EncryptedContentInfoAsn EncryptedContentInfo;
         internal System.Security.Cryptography.Asn1.AttributeAsn[] UnprotectedAttributes;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Version);
             EncryptedContentInfo.Encode(writer);
 
@@ -36,7 +36,7 @@ namespace System.Security.Cryptography.Asn1.Pkcs7
                 writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
                 for (int i = 0; i < UnprotectedAttributes.Length; i++)
                 {
-                    UnprotectedAttributes[i].Encode(writer); 
+                    UnprotectedAttributes[i].Encode(writer);
                 }
                 writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
 
@@ -49,40 +49,34 @@ namespace System.Security.Cryptography.Asn1.Pkcs7
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static EncryptedDataAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out EncryptedDataAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out EncryptedDataAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out EncryptedDataAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out EncryptedDataAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EncryptedDataAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out EncryptedDataAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader collectionReader;
+
 
             if (!sequenceReader.TryReadInt32(out decoded.Version))
             {
                 sequenceReader.ThrowIfNotEmpty();
             }
 
-            System.Security.Cryptography.Asn1.Pkcs7.EncryptedContentInfoAsn.Decode(sequenceReader, out decoded.EncryptedContentInfo);
+            System.Security.Cryptography.Asn1.Pkcs7.EncryptedContentInfoAsn.Decode(ref sequenceReader, rebind, out decoded.EncryptedContentInfo);
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
             {
@@ -95,7 +89,7 @@ namespace System.Security.Cryptography.Asn1.Pkcs7
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index 6a5d283..12ba027 100644 (file)
@@ -18,16 +18,16 @@ namespace System.Security.Cryptography.Asn1
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn PrivateKeyAlgorithm;
         internal ReadOnlyMemory<byte> PrivateKey;
         internal System.Security.Cryptography.Asn1.AttributeAsn[] Attributes;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Version);
             PrivateKeyAlgorithm.Encode(writer);
             writer.WriteOctetString(PrivateKey.Span);
@@ -38,7 +38,7 @@ namespace System.Security.Cryptography.Asn1
                 writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
                 for (int i = 0; i < Attributes.Length; i++)
                 {
-                    Attributes[i].Encode(writer); 
+                    Attributes[i].Encode(writer);
                 }
                 writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
 
@@ -51,44 +51,41 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static PrivateKeyInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out PrivateKeyInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out PrivateKeyInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out PrivateKeyInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out PrivateKeyInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PrivateKeyInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out PrivateKeyInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (!sequenceReader.TryReadUInt8(out decoded.Version))
             {
                 sequenceReader.ThrowIfNotEmpty();
             }
 
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.PrivateKeyAlgorithm);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.PrivateKeyAlgorithm);
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpPrivateKey))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.PrivateKey = tmpPrivateKey;
+                decoded.PrivateKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
@@ -107,7 +104,7 @@ namespace System.Security.Cryptography.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index ceac342..78985e2 100644 (file)
@@ -14,33 +14,34 @@ namespace System.Security.Cryptography.Asn1
     internal partial struct PssParamsAsn
     {
         private static readonly byte[] s_defaultHashAlgorithm = { 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 };
-  
+
         private static readonly byte[] s_defaultMaskGenAlgorithm = { 0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 };
-  
+
         private static readonly byte[] s_defaultSaltLength = { 0x02, 0x01, 0x14 };
-  
+
         private static readonly byte[] s_defaultTrailerField = { 0x02, 0x01, 0x01 };
-  
+
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm;
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenAlgorithm;
         internal int SaltLength;
         internal int TrailerField;
-      
+
 #if DEBUG
         static PssParamsAsn()
         {
             PssParamsAsn decoded = default;
-            AsnReader reader;
+            ReadOnlyMemory<byte> rebind = default;
+            AsnValueReader reader;
 
-            reader = new AsnReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.HashAlgorithm);
+            reader = new AsnValueReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashAlgorithm);
             reader.ThrowIfNotEmpty();
 
-            reader = new AsnReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER);
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.MaskGenAlgorithm);
+            reader = new AsnValueReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.MaskGenAlgorithm);
             reader.ThrowIfNotEmpty();
 
-            reader = new AsnReader(s_defaultSaltLength, AsnEncodingRules.DER);
+            reader = new AsnValueReader(s_defaultSaltLength, AsnEncodingRules.DER);
 
             if (!reader.TryReadInt32(out decoded.SaltLength))
             {
@@ -49,7 +50,7 @@ namespace System.Security.Cryptography.Asn1
 
             reader.ThrowIfNotEmpty();
 
-            reader = new AsnReader(s_defaultTrailerField, AsnEncodingRules.DER);
+            reader = new AsnValueReader(s_defaultTrailerField, AsnEncodingRules.DER);
 
             if (!reader.TryReadInt32(out decoded.TrailerField))
             {
@@ -59,16 +60,16 @@ namespace System.Security.Cryptography.Asn1
             reader.ThrowIfNotEmpty();
         }
 #endif
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
 
             // DEFAULT value handler for HashAlgorithm.
             {
@@ -80,7 +81,7 @@ namespace System.Security.Cryptography.Asn1
                     if (!encoded.SequenceEqual(s_defaultHashAlgorithm))
                     {
                         writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                         writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                     }
                 }
@@ -97,7 +98,7 @@ namespace System.Security.Cryptography.Asn1
                     if (!encoded.SequenceEqual(s_defaultMaskGenAlgorithm))
                     {
                         writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                         writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
                     }
                 }
@@ -114,7 +115,7 @@ namespace System.Security.Cryptography.Asn1
                     if (!encoded.SequenceEqual(s_defaultSaltLength))
                     {
                         writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                         writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
                     }
                 }
@@ -131,7 +132,7 @@ namespace System.Security.Cryptography.Asn1
                     if (!encoded.SequenceEqual(s_defaultTrailerField))
                     {
                         writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                         writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
                     }
                 }
@@ -144,58 +145,52 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static PssParamsAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out PssParamsAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out PssParamsAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out PssParamsAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out PssParamsAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PssParamsAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out PssParamsAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            AsnReader defaultReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            AsnValueReader defaultReader;
+
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
                 explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(explicitReader, out decoded.HashAlgorithm);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref explicitReader, rebind, out decoded.HashAlgorithm);
                 explicitReader.ThrowIfNotEmpty();
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.HashAlgorithm);
+                defaultReader = new AsnValueReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.HashAlgorithm);
             }
 
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
             {
                 explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(explicitReader, out decoded.MaskGenAlgorithm);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref explicitReader, rebind, out decoded.MaskGenAlgorithm);
                 explicitReader.ThrowIfNotEmpty();
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER);
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.MaskGenAlgorithm);
+                defaultReader = new AsnValueReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.MaskGenAlgorithm);
             }
 
 
@@ -212,7 +207,7 @@ namespace System.Security.Cryptography.Asn1
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultSaltLength, AsnEncodingRules.DER);
+                defaultReader = new AsnValueReader(s_defaultSaltLength, AsnEncodingRules.DER);
 
                 if (!defaultReader.TryReadInt32(out decoded.SaltLength))
                 {
@@ -235,7 +230,7 @@ namespace System.Security.Cryptography.Asn1
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultTrailerField, AsnEncodingRules.DER);
+                defaultReader = new AsnValueReader(s_defaultTrailerField, AsnEncodingRules.DER);
 
                 if (!defaultReader.TryReadInt32(out decoded.TrailerField))
                 {
index 4400c76..a5ffdaf 100644 (file)
@@ -22,16 +22,16 @@ namespace System.Security.Cryptography.Asn1
         internal System.Numerics.BigInteger Exponent1;
         internal System.Numerics.BigInteger Exponent2;
         internal System.Numerics.BigInteger Coefficient;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Version);
             writer.WriteInteger(Modulus);
             writer.WriteInteger(PublicExponent);
@@ -48,32 +48,26 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static RSAPrivateKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out RSAPrivateKeyAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out RSAPrivateKeyAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out RSAPrivateKeyAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out RSAPrivateKeyAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out RSAPrivateKeyAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out RSAPrivateKeyAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+
 
             if (!sequenceReader.TryReadUInt8(out decoded.Version))
             {
index 2e513d9..ee46993 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1
     {
         internal System.Numerics.BigInteger Modulus;
         internal System.Numerics.BigInteger PublicExponent;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Modulus);
             writer.WriteInteger(PublicExponent);
             writer.PopSequence(tag);
@@ -34,32 +34,26 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static RSAPublicKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out RSAPublicKeyAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out RSAPublicKeyAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out RSAPublicKeyAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out RSAPublicKeyAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out RSAPublicKeyAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out RSAPublicKeyAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+
             decoded.Modulus = sequenceReader.ReadInteger();
             decoded.PublicExponent = sequenceReader.ReadInteger();
 
index d126552..580692b 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1
     {
         internal int Rc2Version;
         internal ReadOnlyMemory<byte> Iv;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Rc2Version);
             writer.WriteOctetString(Iv.Span);
             writer.PopSequence(tag);
@@ -34,32 +34,29 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static Rc2CbcParameters Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out Rc2CbcParameters decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out Rc2CbcParameters decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out Rc2CbcParameters decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out Rc2CbcParameters decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Rc2CbcParameters decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out Rc2CbcParameters decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (!sequenceReader.TryReadInt32(out decoded.Rc2Version))
             {
@@ -67,9 +64,9 @@ namespace System.Security.Cryptography.Asn1
             }
 
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpIv))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.Iv = tmpIv;
+                decoded.Iv = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index 255b065..f1f44d8 100644 (file)
@@ -20,16 +20,16 @@ namespace System.Security.Cryptography.Asn1
         internal ReadOnlyMemory<byte> Order;
         internal ReadOnlyMemory<byte>? Cofactor;
         internal Oid Hash;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Version);
             FieldID.Encode(writer);
             Curve.Encode(writer);
@@ -54,55 +54,54 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static SpecifiedECDomain Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out SpecifiedECDomain decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out SpecifiedECDomain decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out SpecifiedECDomain decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out SpecifiedECDomain decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SpecifiedECDomain decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out SpecifiedECDomain decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (!sequenceReader.TryReadUInt8(out decoded.Version))
             {
                 sequenceReader.ThrowIfNotEmpty();
             }
 
-            System.Security.Cryptography.Asn1.FieldID.Decode(sequenceReader, out decoded.FieldID);
-            System.Security.Cryptography.Asn1.CurveAsn.Decode(sequenceReader, out decoded.Curve);
+            System.Security.Cryptography.Asn1.FieldID.Decode(ref sequenceReader, rebind, out decoded.FieldID);
+            System.Security.Cryptography.Asn1.CurveAsn.Decode(ref sequenceReader, rebind, out decoded.Curve);
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpBase))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.Base = tmpBase;
+                decoded.Base = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
                 decoded.Base = sequenceReader.ReadOctetString();
             }
 
-            decoded.Order = sequenceReader.ReadIntegerBytes();
+            tmpSpan = sequenceReader.ReadIntegerBytes();
+            decoded.Order = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
             {
-                decoded.Cofactor = sequenceReader.ReadIntegerBytes();
+                tmpSpan = sequenceReader.ReadIntegerBytes();
+                decoded.Cofactor = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
 
 
index 121a4db..24125bc 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Asn1
     {
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn Algorithm;
         internal ReadOnlyMemory<byte> SubjectPublicKey;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             Algorithm.Encode(writer);
             writer.WriteBitString(SubjectPublicKey.Span);
             writer.PopSequence(tag);
@@ -34,37 +34,34 @@ namespace System.Security.Cryptography.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static SubjectPublicKeyInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out SubjectPublicKeyInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out SubjectPublicKeyInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out SubjectPublicKeyInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out SubjectPublicKeyInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SubjectPublicKeyInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out SubjectPublicKeyInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.Algorithm);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.Algorithm);
 
-            if (sequenceReader.TryReadPrimitiveBitStringValue(out _, out ReadOnlyMemory<byte> tmpSubjectPublicKey))
+            if (sequenceReader.TryReadPrimitiveBitStringValue(out _, out tmpSpan))
             {
-                decoded.SubjectPublicKey = tmpSubjectPublicKey;
+                decoded.SubjectPublicKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index 89f0553..0c447e9 100644 (file)
@@ -14,34 +14,34 @@ namespace System.Security.Cryptography.Asn1
     internal partial struct X509ExtensionAsn
     {
         private static readonly 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;
+            AsnValueReader reader;
 
-            reader = new AsnReader(s_defaultCritical, AsnEncodingRules.DER);
+            reader = new AsnValueReader(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))
@@ -51,7 +51,7 @@ namespace System.Security.Cryptography.Asn1
 
                     if (!encoded.SequenceEqual(s_defaultCritical))
                     {
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                     }
                 }
             }
@@ -64,33 +64,30 @@ namespace System.Security.Cryptography.Asn1
         {
             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);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out X509ExtensionAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out X509ExtensionAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out X509ExtensionAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out X509ExtensionAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out X509ExtensionAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader defaultReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader defaultReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.ExtnId = sequenceReader.ReadObjectIdentifier();
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Boolean))
@@ -99,14 +96,14 @@ namespace System.Security.Cryptography.Asn1
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultCritical, AsnEncodingRules.DER);
+                defaultReader = new AsnValueReader(s_defaultCritical, AsnEncodingRules.DER);
                 decoded.Critical = defaultReader.ReadBoolean();
             }
 
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpExtnValue))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.ExtnValue = tmpExtnValue;
+                decoded.ExtnValue = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index 50abbd2..9313313 100644 (file)
@@ -15,7 +15,7 @@
   <xsl:template match="node()[name()]" mode="FieldDef" priority="-9">
     <xsl:message terminate="yes">Error, unknown FieldDef node [<xsl:copy-of select="."/>]</xsl:message>
   </xsl:template>
-  
+
   <xsl:template match="node()[name()]" mode="CollectionElementType" priority="-9">
     <xsl:message terminate="yes">Error, unknown CollectionElementType node (<xsl:value-of select="local-name()"/>) [<xsl:copy-of select=".."/>]</xsl:message>
   </xsl:template>
     <xsl:apply-templates/>
   </xsl:template>
 
+  <xsl:variable name="hasMemoryField" xml:space="default">
+    <xsl:choose>
+      <xsl:when test="//asn:AnyValue | //asn:Integer[@backingType='ReadOnlyMemory'] | //asn:BitString | //asn:OctetString">1</xsl:when>
+      <xsl:otherwise>0</xsl:otherwise>
+    </xsl:choose>
+  </xsl:variable>
+
   <xsl:template match="asn:Sequence">// 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.
@@ -56,25 +63,26 @@ namespace <xsl:value-of select="@namespace" />
     [StructLayout(LayoutKind.Sequential)]
     internal partial struct <xsl:value-of select="@name" />
     {<xsl:apply-templates mode="Validate" /><xsl:apply-templates mode="DefaultFieldDef" /><xsl:apply-templates mode="FieldDef" />
-      <xsl:if test="*[@defaultDerInit]">
+<xsl:if test="*[@defaultDerInit]">
 #if DEBUG
         static <xsl:value-of select="@name" />()
         {
-            <xsl:value-of select="@name" /> decoded = default;
-            AsnReader reader;<xsl:if test="asn:SequenceOf[@defaultDerInit] | asn:SetOf[@defaultDerInit]">
-            AsnReader collectionReader;</xsl:if><xsl:apply-templates mode="DefaultFieldVerify" />
+            <xsl:value-of select="@name" /> decoded = default;<xsl:if test="asn:AsnType[@defaultDerInit] | *[@defaultDerInit]/asn:AsnType">
+            ReadOnlyMemory&lt;byte&gt; rebind = default;</xsl:if>
+            AsnValueReader reader;<xsl:if test="asn:SequenceOf[@defaultDerInit] | asn:SetOf[@defaultDerInit]">
+            AsnValueReader collectionReader;</xsl:if><xsl:apply-templates mode="DefaultFieldVerify" />
         }
 #endif
- </xsl:if>
+</xsl:if>
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            <xsl:apply-templates mode="Encode" />
+<xsl:apply-templates mode="Encode" />
             writer.PopSequence(tag);
         }
 
@@ -82,35 +90,32 @@ namespace <xsl:value-of select="@namespace" />
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static <xsl:value-of select="@name" /> Decode(Asn1Tag expectedTag, ReadOnlyMemory&lt;byte&gt; encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out <xsl:value-of select="@name" /> decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out <xsl:value-of select="@name" /> decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out <xsl:value-of select="@name" /> decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory&lt;byte&gt; rebind, out <xsl:value-of select="@name" /> decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out <xsl:value-of select="@name" /> decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory&lt;byte&gt; rebind, out <xsl:value-of select="@name" /> decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);<xsl:if test="*[@explicitTag]">
-            AsnReader explicitReader;</xsl:if><xsl:if test="*[@defaultDerInit]">
-            AsnReader defaultReader;</xsl:if><xsl:if test="asn:SequenceOf | asn:SetOf">
-            AsnReader collectionReader;</xsl:if>
-            <xsl:apply-templates mode="Decode" />
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);<xsl:if test="*[@explicitTag]">
+            AsnValueReader explicitReader;</xsl:if><xsl:if test="*[@defaultDerInit]">
+            AsnValueReader defaultReader;</xsl:if><xsl:if test="asn:SequenceOf | asn:SetOf">
+            AsnValueReader collectionReader;</xsl:if><xsl:if test="$hasMemoryField &gt; 0">
+            ReadOnlySpan&lt;byte&gt; rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan&lt;byte&gt; tmpSpan;</xsl:if>
+<xsl:apply-templates mode="Decode" />
 
             sequenceReader.ThrowIfNotEmpty();
         }
@@ -149,14 +154,14 @@ namespace <xsl:value-of select="@namespace" />
 
                 usedTags.Add(tag, fieldName);
             };
-            <xsl:apply-templates mode="EnsureUniqueTag" />
+<xsl:apply-templates mode="EnsureUniqueTag" />
         }
 #endif
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            <xsl:apply-templates mode="EncodeChoice" />
+            bool wroteValue = false;
+<xsl:apply-templates mode="EncodeChoice" />
             if (!wroteValue)
             {
                 throw new CryptographicException();
@@ -165,23 +170,23 @@ namespace <xsl:value-of select="@namespace" />
 
         internal static <xsl:value-of select="@name" /> Decode(ReadOnlyMemory&lt;byte&gt; encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out <xsl:value-of select="@name" /> decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out <xsl:value-of select="@name" /> decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out <xsl:value-of select="@name" /> decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory&lt;byte&gt; rebind, out <xsl:value-of select="@name" /> decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();<xsl:if test="*[@explicitTag]">
-            AsnReader explicitReader;</xsl:if><xsl:if test="asn:SequenceOf | asn:SetOf">
-            AsnReader collectionReader;</xsl:if>
-            <xsl:apply-templates select="*" mode="Decode" />
+            AsnValueReader explicitReader;</xsl:if><xsl:if test="asn:SequenceOf | asn:SetOf">
+            AsnValueReader collectionReader;</xsl:if><xsl:if test="$hasMemoryField &gt; 0">
+            ReadOnlySpan&lt;byte&gt; rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan&lt;byte&gt; tmpSpan;</xsl:if>
+<xsl:apply-templates select="*" mode="Decode" />
             else
             {
                 throw new CryptographicException();
@@ -194,11 +199,11 @@ namespace <xsl:value-of select="@namespace" />
   <xsl:template match="*[@defaultDerInit and @optional]" mode="Validate">
     <xsl:message terminate="yes">Error: defaultDerInit and optional both specified in [<xsl:copy-of select="."/>]</xsl:message>
   </xsl:template>
-  
+
   <xsl:template match="*[@implicitTag and @explicitTag]" mode="Validate">
     <xsl:message terminate="yes">Error: implicitTag and explicitTag both specified in [<xsl:copy-of select="."/>]</xsl:message>
   </xsl:template>
-    
+
   <xsl:template match="*[@implicitTag and @universalTagNumber]" mode="Validate">
     <xsl:message terminate="yes">Error: implicitTag and universalTagNumber both specified in [<xsl:copy-of select="."/>]</xsl:message>
   </xsl:template>
@@ -209,11 +214,11 @@ namespace <xsl:value-of select="@namespace" />
 
   <xsl:template match="*[@defaultDerInit]" mode="DefaultFieldDef">
         private static readonly byte[] <xsl:call-template name="DefaultValueField"/> = { <xsl:value-of select="@defaultDerInit"/> };
-  </xsl:template>
+</xsl:template>
 
   <xsl:template match="*[@defaultDerInit]" mode="DefaultFieldVerify">
 
-            reader = new AsnReader(<xsl:call-template name="DefaultValueField"/>, AsnEncodingRules.DER);<xsl:apply-templates select="." mode="DecodeSimpleValue"><xsl:with-param name="readerName" select="'reader'"/></xsl:apply-templates>
+            reader = new AsnValueReader(<xsl:call-template name="DefaultValueField"/>, AsnEncodingRules.DER);<xsl:apply-templates select="." mode="DecodeSimpleValue"><xsl:with-param name="readerName" select="'reader'"/></xsl:apply-templates>
             reader.ThrowIfNotEmpty();</xsl:template>
 
   <xsl:template match="*" mode="EnsureUniqueTag" xml:space="default">
@@ -228,7 +233,7 @@ namespace <xsl:value-of select="@namespace" />
   <xsl:template match="*" mode="Encode" xml:space="default">
     <xsl:choose>
       <xsl:when test="@defaultDerInit and not(@explicitTag)" xml:space="preserve">
-        
+
             // DEFAULT value handler for <xsl:value-of select="@name" />.
             {
                 using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
@@ -240,7 +245,7 @@ namespace <xsl:value-of select="@namespace" />
 
                     if (!encoded.SequenceEqual(<xsl:call-template name="DefaultValueField"/>))
                     {
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                     }
                 }
             }
@@ -253,7 +258,7 @@ namespace <xsl:value-of select="@namespace" />
       </xsl:otherwise>
     </xsl:choose>
   </xsl:template>
-  
+
   <!-- Struct OPTIONAL -->
   <xsl:template match="asn:AsnType | asn:AnyValue | asn:Boolean | asn:Integer | asn:BitString | asn:NamedBitList | asn:OctetString | asn:Enumerated | asn:UtcTime | asn:GeneralizedTime" mode="EncodeOptional">
 
@@ -276,7 +281,7 @@ namespace <xsl:value-of select="@namespace" />
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                <xsl:apply-templates select="." mode="EncodeValue"><xsl:with-param name="indent" select="'    '"/></xsl:apply-templates>
+<xsl:apply-templates select="." mode="EncodeValue"><xsl:with-param name="indent" select="'    '"/></xsl:apply-templates>
                 wroteValue = true;
             }
 </xsl:template>
@@ -287,7 +292,7 @@ namespace <xsl:value-of select="@namespace" />
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                <xsl:apply-templates select="." mode="EncodeValue"><xsl:with-param name="indent" select="'    '"/></xsl:apply-templates>
+<xsl:apply-templates select="." mode="EncodeValue"><xsl:with-param name="indent" select="'    '"/></xsl:apply-templates>
                 wroteValue = true;
             }
 </xsl:template>
@@ -310,7 +315,7 @@ namespace <xsl:value-of select="@namespace" />
                     if (!encoded.SequenceEqual(<xsl:call-template name="DefaultValueField"/>))
                     {
                         writer.PushSequence(<xsl:call-template name="ContextTag" />);
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                         writer.PopSequence(<xsl:call-template name="ContextTag" />);
                     }
                 }
@@ -324,7 +329,7 @@ namespace <xsl:value-of select="@namespace" />
       </xsl:otherwise>
     </xsl:choose>
   </xsl:template>
-  
+
   <xsl:template match="*" mode="Decode" xml:space="default">
     <xsl:choose>
       <xsl:when test="parent::asn:Choice">
@@ -402,7 +407,7 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:if test="1" xml:space="preserve">
             <xsl:value-of select="$indent"/><xsl:value-of select="$name"/><xsl:if test="$nullable">.Value</xsl:if>.Encode(<xsl:value-of select="$writerName"/><xsl:call-template name="MaybeImplicitCallS"/>);</xsl:if>
   </xsl:template>
-  
+
   <xsl:template match="asn:AsnType" mode="DecodeSimpleValue" xml:space="default">
     <xsl:param name="readerName" />
     <xsl:param name="indent" />
@@ -410,14 +415,14 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:choose>
       <xsl:when test="@optional | parent::asn:Choice" xml:space="preserve">
             <xsl:value-of select="$indent"/><xsl:value-of select="@typeName"/> tmp<xsl:value-of select="@name"/>;
-            <xsl:value-of select="$indent"/><xsl:value-of select="@typeName"/>.Decode(<xsl:value-of select="$readerName"/>, <xsl:call-template name="MaybeImplicitCallP"/>out tmp<xsl:value-of select="@name"/>);
+            <xsl:value-of select="$indent"/><xsl:value-of select="@typeName"/>.Decode(ref <xsl:value-of select="$readerName"/>, <xsl:call-template name="MaybeImplicitCallP"/>rebind, out tmp<xsl:value-of select="@name"/>);
             <xsl:value-of select="$indent"/><xsl:value-of select="$name"/> = tmp<xsl:value-of select="@name"/>;
 </xsl:when>
       <xsl:otherwise xml:space="preserve">
-            <xsl:value-of select="$indent"/><xsl:value-of select="@typeName"/>.Decode(<xsl:value-of select="$readerName"/>, <xsl:call-template name="MaybeImplicitCallP"/>out <xsl:value-of select="$name"/>);</xsl:otherwise>
+            <xsl:value-of select="$indent"/><xsl:value-of select="@typeName"/>.Decode(ref <xsl:value-of select="$readerName"/>, <xsl:call-template name="MaybeImplicitCallP"/>rebind, out <xsl:value-of select="$name"/>);</xsl:otherwise>
     </xsl:choose>
   </xsl:template>
-  
+
   <xsl:template match="asn:AsnType" mode="DefaultTag">Asn1Tag.Sequence</xsl:template>
 
   <xsl:template match="asn:AnyValue" mode="FieldDef">
@@ -450,16 +455,16 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:param name="name" select="concat('decoded.', @name)"/>
     <xsl:choose>
         <xsl:when test="@optional | parent::asn:Choice" xml:space="preserve">
-            <xsl:value-of select="$indent"/><xsl:value-of select="$name"/> = <xsl:value-of select="$readerName"/>.ReadEncodedValue();</xsl:when>
+            <xsl:value-of select="$indent"/>tmpSpan = <xsl:value-of select="$readerName"/>.ReadEncodedValue();<xsl:call-template name="RebindMemory"><xsl:with-param name="name" select="$name"/><xsl:with-param name="indent" select="$indent"/></xsl:call-template></xsl:when>
         <xsl:when test="@implicitTag | @universalTagNumber" xml:space="preserve">
             <xsl:value-of select="$indent"/>if (!<xsl:value-of select="$readerName"/>.PeekTag().HasSameClassAndValue(<xsl:call-template name="DefaultOrContextTag"/>))
             <xsl:value-of select="$indent"/>{
             <xsl:value-of select="$indent"/>    throw new CryptographicException();
             <xsl:value-of select="$indent"/>}
 
-            <xsl:value-of select="$indent"/><xsl:value-of select="$name"/> = <xsl:value-of select="$readerName"/>.ReadEncodedValue();</xsl:when>
+            <xsl:value-of select="$indent"/>tmpSpan = <xsl:value-of select="$readerName"/>.ReadEncodedValue();<xsl:call-template name="RebindMemory"><xsl:with-param name="name" select="$name"/><xsl:with-param name="indent" select="$indent"/></xsl:call-template></xsl:when>
         <xsl:otherwise xml:space="preserve">
-            <xsl:value-of select="$indent"/><xsl:value-of select="$name"/> = <xsl:value-of select="$readerName"/>.ReadEncodedValue();</xsl:otherwise>
+            <xsl:value-of select="$indent"/>tmpSpan = <xsl:value-of select="$readerName"/>.ReadEncodedValue();<xsl:call-template name="RebindMemory"><xsl:with-param name="name" select="$name"/><xsl:with-param name="indent" select="$indent"/></xsl:call-template></xsl:otherwise>
     </xsl:choose>
   </xsl:template>
 
@@ -480,7 +485,7 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:if test="1" xml:space="preserve">
             <xsl:value-of select="$indent"/><xsl:value-of select="$writerName"/>.WriteBoolean(<xsl:call-template name="MaybeImplicitCallP"/><xsl:value-of select="$name"/><xsl:if test="$nullable">.Value</xsl:if>);</xsl:if>
   </xsl:template>
-  
+
   <xsl:template match="asn:Boolean" mode="DecodeSimpleValue" xml:space="default">
     <xsl:param name="readerName" />
     <xsl:param name="indent" />
@@ -488,12 +493,12 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:if test="1" xml:space="preserve">
             <xsl:value-of select="$indent"/><xsl:value-of select="$name"/> = <xsl:value-of select="$readerName"/>.ReadBoolean(<xsl:call-template name="MaybeImplicitCall0"/>);</xsl:if>
   </xsl:template>
-  
+
   <xsl:template match="asn:Boolean" mode="DefaultTag">Asn1Tag.Boolean</xsl:template>
 
   <xsl:template match="asn:Integer[not(@backingType)] | asn:Integer[@backingType = 'BigInteger']" mode="FieldDef">
         internal System.Numerics.BigInteger<xsl:if test="@optional | parent::asn:Choice">?</xsl:if> <xsl:value-of select="@name" />;</xsl:template>
-  
+
   <xsl:template match="asn:Integer[@backingType = 'ReadOnlyMemory']" mode="FieldDef">
         internal ReadOnlyMemory&lt;byte&gt;<xsl:if test="@optional | parent::asn:Choice">?</xsl:if> <xsl:value-of select="@name" />;</xsl:template>
 
@@ -539,7 +544,7 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:param name="indent" />
     <xsl:param name="name" select="concat('decoded.', @name)"/>
     <xsl:if test="1" xml:space="preserve">
-            <xsl:value-of select="$indent"/><xsl:value-of select="$name"/> = <xsl:value-of select="$readerName"/>.ReadIntegerBytes(<xsl:call-template name="MaybeImplicitCall0"/>);</xsl:if>
+            <xsl:value-of select="$indent"/>tmpSpan = <xsl:value-of select="$readerName"/>.ReadIntegerBytes(<xsl:call-template name="MaybeImplicitCall0"/>);<xsl:call-template name="RebindMemory"><xsl:with-param name="name" select="$name"/><xsl:with-param name="indent" select="$indent"/></xsl:call-template></xsl:if>
   </xsl:template>
 
   <xsl:template match="asn:Integer[@backingType = 'byte']" mode="DecodeSimpleValue" xml:space="default">
@@ -616,9 +621,8 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:param name="name" select="concat('decoded.', @name)"/>
     <xsl:if test="1" xml:space="preserve">
 
-            <xsl:value-of select="$indent"/>if (<xsl:value-of select="$readerName"/>.TryReadPrimitiveBitStringValue(<xsl:call-template name="MaybeImplicitCallP"/>out _, out ReadOnlyMemory&lt;byte&gt; tmp<xsl:value-of select="@name"/>))
-            <xsl:value-of select="$indent"/>{
-            <xsl:value-of select="$indent"/>    <xsl:value-of select="$name"/> = tmp<xsl:value-of select="@name"/>;
+            <xsl:value-of select="$indent"/>if (<xsl:value-of select="$readerName"/>.TryReadPrimitiveBitStringValue(<xsl:call-template name="MaybeImplicitCallP"/>out _, out tmpSpan))
+            <xsl:value-of select="$indent"/>{<xsl:call-template name="RebindMemory"><xsl:with-param name="name" select="$name"/><xsl:with-param name="indent" select="concat('    ', $indent)"/></xsl:call-template>
             <xsl:value-of select="$indent"/>}
             <xsl:value-of select="$indent"/>else
             <xsl:value-of select="$indent"/>{
@@ -673,9 +677,8 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:param name="name" select="concat('decoded.', @name)"/>
     <xsl:if test="1" xml:space="preserve">
 
-            <xsl:value-of select="$indent"/>if (<xsl:value-of select="$readerName"/>.TryReadPrimitiveOctetStringBytes(<xsl:call-template name="MaybeImplicitCallP"/>out ReadOnlyMemory&lt;byte&gt; tmp<xsl:value-of select="@name"/>))
-            <xsl:value-of select="$indent"/>{
-            <xsl:value-of select="$indent"/>    <xsl:value-of select="$name"/> = tmp<xsl:value-of select="@name"/>;
+            <xsl:value-of select="$indent"/>if (<xsl:value-of select="$readerName"/>.TryReadPrimitiveOctetStringBytes(<xsl:call-template name="MaybeImplicitCallP"/>out tmpSpan))
+            <xsl:value-of select="$indent"/>{<xsl:call-template name="RebindMemory"><xsl:with-param name="name" select="$name"/><xsl:with-param name="indent" select="concat('    ', $indent)"/></xsl:call-template>
             <xsl:value-of select="$indent"/>}
             <xsl:value-of select="$indent"/>else
             <xsl:value-of select="$indent"/>{
@@ -745,7 +748,7 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:if test="1" xml:space="preserve">
             <xsl:value-of select="$indent"/><xsl:value-of select="$writerName"/>.WriteEnumeratedValue(<xsl:call-template name="MaybeImplicitCallP"/><xsl:value-of select="$name"/><xsl:if test="$nullable">.Value</xsl:if>);</xsl:if>
   </xsl:template>
-  
+
   <xsl:template match="asn:Enumerated" mode="DecodeSimpleValue" xml:space="default">
     <xsl:param name="readerName" />
     <xsl:param name="indent" />
@@ -753,7 +756,7 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:if test="1" xml:space="preserve">
             <xsl:value-of select="$indent"/><xsl:value-of select="$name"/> = <xsl:value-of select="$readerName"/>.ReadEnumeratedValue&lt;<xsl:value-of select="@backingType"/>&gt;(<xsl:call-template name="MaybeImplicitCall0"/>);</xsl:if>
   </xsl:template>
-  
+
   <xsl:template match="asn:Enumerated" mode="DefaultTag">Asn1Tag.Enumerated</xsl:template>
 
   <!-- All character string types -->
@@ -769,7 +772,7 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:if test="1" xml:space="preserve">
             <xsl:value-of select="$indent"/><xsl:value-of select="$writerName"/>.WriteCharacterString(<xsl:call-template name="MaybeImplicitCallP"/>UniversalTagNumber.<xsl:value-of select="local-name()"/>, <xsl:value-of select="$name"/>);</xsl:if>
   </xsl:template>
-  
+
   <xsl:template match="asn:UTF8String | asn:PrintableString | asn:T61String | asn:IA5String | asn:VisibleString | asn:BMPString" mode="DecodeSimpleValue" xml:space="default">
     <xsl:param name="readerName" />
     <xsl:param name="indent" />
@@ -777,7 +780,7 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:if test="1" xml:space="preserve">
             <xsl:value-of select="$indent"/><xsl:value-of select="$name"/> = <xsl:value-of select="$readerName"/>.ReadCharacterString(<xsl:call-template name="MaybeImplicitCallP"/>UniversalTagNumber.<xsl:value-of select="local-name()"/>);</xsl:if>
   </xsl:template>
-  
+
   <xsl:template match="asn:UTF8String | asn:PrintableString | asn:T61String | asn:IA5String | asn:VisibleString | asn:BMPString" mode="DefaultTag">new Asn1Tag(UniversalTagNumber.<xsl:value-of select="local-name()"/>)</xsl:template>
 
   <xsl:template match="asn:SequenceOf | asn:SetOf" mode="FieldDef">
@@ -796,12 +799,12 @@ namespace <xsl:value-of select="@namespace" />
 
             <xsl:value-of select="$indent"/><xsl:value-of select="$writerName"/>.Push<xsl:value-of select="$collNoun"/>(<xsl:call-template name="MaybeImplicitCall0"/>);
             <xsl:value-of select="$indent"/>for (int i = 0; i &lt; <xsl:value-of select="@name"/>.Length; i++)
-            <xsl:value-of select="$indent"/>{<xsl:apply-templates mode="EncodeSimpleValue"><xsl:with-param name="name" select="concat(@name, '[i]')"/><xsl:with-param name="writerName" select="$writerName"/><xsl:with-param name="indent" select="concat('    ', $indent)"/></xsl:apply-templates> 
+            <xsl:value-of select="$indent"/>{<xsl:apply-templates mode="EncodeSimpleValue"><xsl:with-param name="name" select="concat(@name, '[i]')"/><xsl:with-param name="writerName" select="$writerName"/><xsl:with-param name="indent" select="concat('    ', $indent)"/></xsl:apply-templates>
             <xsl:value-of select="$indent"/>}
             <xsl:value-of select="$indent"/><xsl:value-of select="$writerName"/>.Pop<xsl:value-of select="$collNoun"/>(<xsl:call-template name="MaybeImplicitCall0"/>);
 </xsl:if>
   </xsl:template>
-  
+
   <xsl:template match="asn:SequenceOf | asn:SetOf" mode="DecodeSimpleValue" xml:space="default">
     <xsl:param name="readerName" />
     <xsl:param name="indent" />
@@ -820,7 +823,7 @@ namespace <xsl:value-of select="@namespace" />
             <xsl:value-of select="$indent"/>    <xsl:apply-templates mode="CollectionElementType"/> tmpItem;
 
             <xsl:value-of select="$indent"/>    while (collectionReader.HasData)
-            <xsl:value-of select="$indent"/>    {<xsl:apply-templates mode="DecodeSimpleValue"><xsl:with-param name="name" select="'tmpItem'"/><xsl:with-param name="readerName" select="'collectionReader'"/><xsl:with-param name="indent" select="concat('        ', $indent)"/></xsl:apply-templates> 
+            <xsl:value-of select="$indent"/>    {<xsl:apply-templates mode="DecodeSimpleValue"><xsl:with-param name="name" select="'tmpItem'"/><xsl:with-param name="readerName" select="'collectionReader'"/><xsl:with-param name="indent" select="concat('        ', $indent)"/></xsl:apply-templates>
             <xsl:value-of select="$indent"/>        tmpList.Add(tmpItem);
             <xsl:value-of select="$indent"/>    }
 
@@ -846,7 +849,7 @@ namespace <xsl:value-of select="@namespace" />
     <xsl:if test="1" xml:space="preserve">
             <xsl:value-of select="$indent"/><xsl:value-of select="$writerName"/>.WriteUtcTime(<xsl:call-template name="MaybeImplicitCallP"/><xsl:value-of select="$name"/><xsl:if test="$nullable">.Value</xsl:if>);</xsl:if>
   </xsl:template>
-  
+
   <xsl:template match="asn:UtcTime" mode="DecodeSimpleValue" xml:space="default">
     <xsl:param name="readerName" />
     <xsl:param name="indent" />
@@ -858,9 +861,9 @@ namespace <xsl:value-of select="@namespace" />
             <xsl:value-of select="$indent"/><xsl:value-of select="$name"/> = <xsl:value-of select="$readerName"/>.ReadUtcTime(<xsl:call-template name="MaybeImplicitCall0"/>);</xsl:otherwise>
     </xsl:choose>
   </xsl:template>
-  
+
   <xsl:template match="asn:UtcTime" mode="DefaultTag">Asn1Tag.UtcTime</xsl:template>
-  
+
   <xsl:template match="asn:GeneralizedTime" mode="EncodeSimpleValue" xml:space="default">
     <xsl:param name="writerName"/>
     <xsl:param name="indent" />
@@ -873,7 +876,7 @@ namespace <xsl:value-of select="@namespace" />
             <xsl:value-of select="$indent"/><xsl:value-of select="$writerName"/>.WriteGeneralizedTime(<xsl:call-template name="MaybeImplicitCallP"/><xsl:value-of select="$name"/><xsl:if test="$nullable">.Value</xsl:if>);</xsl:otherwise>
     </xsl:choose>
   </xsl:template>
-  
+
   <xsl:template match="asn:GeneralizedTime" mode="DecodeSimpleValue" xml:space="default">
     <xsl:param name="readerName" />
     <xsl:param name="indent" />
@@ -885,7 +888,7 @@ namespace <xsl:value-of select="@namespace" />
             <xsl:value-of select="$indent"/><xsl:value-of select="$name"/> = <xsl:value-of select="$readerName"/>.ReadGeneralizedTime(<xsl:call-template name="MaybeImplicitCall0"/>);</xsl:otherwise>
     </xsl:choose>
   </xsl:template>
-  
+
   <xsl:template match="asn:GeneralizedTime" mode="DefaultTag">Asn1Tag.GeneralizedTime</xsl:template>
 
   <!-- ReadBoolean() vs ReadBoolean(tag) -->
@@ -897,14 +900,21 @@ namespace <xsl:value-of select="@namespace" />
   <!-- Encode(writer) vs Encode(writer, tag) -->
   <xsl:template name="MaybeImplicitCallS"><xsl:if test="@implicitTag">, <xsl:call-template name="ContextTag"/></xsl:if></xsl:template>
 
+  <xsl:template name="RebindMemory" xml:space="default">
+    <xsl:param name="name"/>
+    <xsl:param name="indent"/>
+    <xsl:if test="1" xml:space="preserve">
+            <xsl:value-of select="$indent"/><xsl:value-of select="$name"/> = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();</xsl:if>
+  </xsl:template>
+
   <xsl:template name="ContextTag">new Asn1Tag(TagClass.ContextSpecific, <xsl:value-of select="@implicitTag | @explicitTag"/>)</xsl:template>
-  
+
   <xsl:template name="DefaultValueField">s_default<xsl:value-of select="@name"/></xsl:template>
 
   <xsl:template name="DefaultValueDecoder"><xsl:if test="@defaultDerInit">
             else
             {
-                defaultReader = new AsnReader(<xsl:call-template name="DefaultValueField"/>, AsnEncodingRules.DER);<xsl:apply-templates select="." mode="DecodeSimpleValue"><xsl:with-param name="readerName" select="'defaultReader'"/><xsl:with-param name="indent" select="'    '"/></xsl:apply-templates>
+                defaultReader = new AsnValueReader(<xsl:call-template name="DefaultValueField"/>, AsnEncodingRules.DER);<xsl:apply-templates select="." mode="DecodeSimpleValue"><xsl:with-param name="readerName" select="'defaultReader'"/><xsl:with-param name="indent" select="'    '"/></xsl:apply-templates>
             }</xsl:if></xsl:template>
 
   <xsl:template name="DefaultOrContextTag" xml:space="default">
index c475b99..e777cc1 100644 (file)
@@ -9,18 +9,18 @@ using System.Diagnostics;
 #nullable enable
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         /// <summary>
         ///   Reads the next value as a BIT STRING with tag UNIVERSAL 3, returning the contents
-        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        ///   as a <see cref="ReadOnlySpan{T}"/> over the original data.
         /// </summary>
         /// <param name="unusedBitCount">
         ///   On success, receives the number of bits in the last byte which were reported as
         ///   "unused" by the writer.
         /// </param>
         /// <param name="value">
-        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
+        ///   On success, receives a <see cref="ReadOnlySpan{T}"/> over the original data
         ///   corresponding to the value of the BIT STRING.
         /// </param>
         /// <returns>
@@ -33,12 +33,12 @@ namespace System.Security.Cryptography.Asn1
         ///   the contents are not valid under the current encoding rules
         /// </exception>
         /// <seealso cref="TryCopyBitStringBytes(Span{byte},out int,out int)"/>
-        public bool TryReadPrimitiveBitStringValue(out int unusedBitCount, out ReadOnlyMemory<byte> value)
+        public bool TryReadPrimitiveBitStringValue(out int unusedBitCount, out ReadOnlySpan<byte> value)
             => TryReadPrimitiveBitStringValue(Asn1Tag.PrimitiveBitString, out unusedBitCount, out value);
 
         /// <summary>
         ///   Reads the next value as a BIT STRING with a specified tag, returning the contents
-        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        ///   as a <see cref="ReadOnlySpan{T}"/> over the original data.
         /// </summary>
         /// <param name="expectedTag">The tag to check for before reading.</param>
         /// <param name="unusedBitCount">
@@ -46,7 +46,7 @@ namespace System.Security.Cryptography.Asn1
         ///   "unused" by the writer.
         /// </param>
         /// <param name="value">
-        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
+        ///   On success, receives a <see cref="ReadOnlySpan{T}"/> over the original data
         ///   corresponding to the value of the BIT STRING.
         /// </param>
         /// <returns>
@@ -68,7 +68,7 @@ namespace System.Security.Cryptography.Asn1
         public bool TryReadPrimitiveBitStringValue(
             Asn1Tag expectedTag,
             out int unusedBitCount,
-            out ReadOnlyMemory<byte> value)
+            out ReadOnlySpan<byte> value)
         {
             bool isPrimitive = TryReadPrimitiveBitStringValue(
                 expectedTag,
@@ -83,10 +83,10 @@ namespace System.Security.Cryptography.Asn1
             {
                 // A BER reader which encountered a situation where an "unused" bit was not
                 // set to 0.
-                if (value.Length != 0 && normalizedLastByte != value.Span[value.Length - 1])
+                if (value.Length != 0 && normalizedLastByte != value[value.Length - 1])
                 {
                     unusedBitCount = 0;
-                    value = default(ReadOnlyMemory<byte>);
+                    value = default;
                     return false;
                 }
 
@@ -119,7 +119,7 @@ namespace System.Security.Cryptography.Asn1
         ///   the length encoding is not valid under the current encoding rules --OR--
         ///   the contents are not valid under the current encoding rules
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveBitStringValue(out int,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveBitStringValue(out int,out ReadOnlySpan{byte})"/>
         /// <seealso cref="ReadBitString(out int)"/>
         public bool TryCopyBitStringBytes(
             Span<byte> destination,
@@ -162,7 +162,7 @@ namespace System.Security.Cryptography.Asn1
         ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
         ///   the method
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveBitStringValue(Asn1Tag,out int,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveBitStringValue(Asn1Tag,out int,out ReadOnlySpan{byte})"/>
         /// <seealso cref="ReadBitString(Asn1Tag,out int)"/>
         public bool TryCopyBitStringBytes(
             Asn1Tag expectedTag,
@@ -176,7 +176,7 @@ namespace System.Security.Cryptography.Asn1
                 out int? contentsLength,
                 out int headerLength,
                 out unusedBitCount,
-                out ReadOnlyMemory<byte> value,
+                out ReadOnlySpan<byte> value,
                 out byte normalizedLastByte))
             {
                 if (value.Length > destination.Length)
@@ -213,86 +213,6 @@ namespace System.Security.Cryptography.Asn1
         }
 
         /// <summary>
-        ///   Reads the next value as a BIT STRING with tag UNIVERSAL 3, copying the value
-        ///   into a provided destination buffer.
-        /// </summary>
-        /// <param name="destination">The buffer in which to write.</param>
-        /// <param name="unusedBitCount">
-        ///   On success, receives the number of bits in the last byte which were reported as
-        ///   "unused" by the writer.
-        /// </param>
-        /// <param name="bytesWritten">
-        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
-        /// </param>
-        /// <returns>
-        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
-        ///   length to receive the value, otherwise
-        ///   <c>false</c> and the reader does not advance.
-        /// </returns>
-        /// <exception cref="CryptographicException">
-        ///   the next value does not have the correct tag --OR--
-        ///   the length encoding is not valid under the current encoding rules --OR--
-        ///   the contents are not valid under the current encoding rules
-        /// </exception>
-        /// <seealso cref="TryReadPrimitiveBitStringValue(out int,out ReadOnlyMemory{byte})"/>
-        /// <seealso cref="ReadBitString(out int)"/>
-        public bool TryCopyBitStringBytes(
-            ArraySegment<byte> destination,
-            out int unusedBitCount,
-            out int bytesWritten)
-        {
-            return TryCopyBitStringBytes(
-                Asn1Tag.PrimitiveBitString,
-                destination.AsSpan(),
-                out unusedBitCount,
-                out bytesWritten);
-        }
-
-        /// <summary>
-        ///   Reads the next value as a BIT STRING with a specified tag, copying the value
-        ///   into a provided destination buffer.
-        /// </summary>
-        /// <param name="expectedTag">The tag to check for before reading.</param>
-        /// <param name="destination">The buffer in which to write.</param>
-        /// <param name="unusedBitCount">
-        ///   On success, receives the number of bits in the last byte which were reported as
-        ///   "unused" by the writer.
-        /// </param>
-        /// <param name="bytesWritten">
-        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
-        /// </param>
-        /// <returns>
-        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
-        ///   length to receive the value, otherwise
-        ///   <c>false</c> and the reader does not advance.
-        /// </returns>
-        /// <exception cref="CryptographicException">
-        ///   the next value does not have the correct tag --OR--
-        ///   the length encoding is not valid under the current encoding rules --OR--
-        ///   the contents are not valid under the current encoding rules
-        /// </exception>
-        /// <exception cref="ArgumentException">
-        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
-        ///   <see cref="TagClass.Universal"/>, but
-        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
-        ///   the method
-        /// </exception>
-        /// <seealso cref="TryReadPrimitiveBitStringValue(Asn1Tag,out int,out ReadOnlyMemory{byte})"/>
-        /// <seealso cref="ReadBitString(Asn1Tag,out int)"/>
-        public bool TryCopyBitStringBytes(
-            Asn1Tag expectedTag,
-            ArraySegment<byte> destination,
-            out int unusedBitCount,
-            out int bytesWritten)
-        {
-            return TryCopyBitStringBytes(
-                expectedTag,
-                destination.AsSpan(),
-                out unusedBitCount,
-                out bytesWritten);
-        }
-
-        /// <summary>
         ///   Reads the next value as a BIT STRING with tag UNIVERSAL 3, returning the value
         ///   in a byte array.
         /// </summary>
@@ -308,7 +228,7 @@ namespace System.Security.Cryptography.Asn1
         ///   the length encoding is not valid under the current encoding rules --OR--
         ///   the contents are not valid under the current encoding rules
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveBitStringValue(out int,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveBitStringValue(out int,out ReadOnlySpan{byte})"/>
         /// <seealso cref="TryCopyBitStringBytes(Span{byte},out int,out int)"/>
         public byte[] ReadBitString(out int unusedBitCount)
         {
@@ -338,21 +258,21 @@ namespace System.Security.Cryptography.Asn1
         ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
         ///   the method
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveBitStringValue(Asn1Tag,out int,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveBitStringValue(Asn1Tag,out int,out ReadOnlySpan{byte})"/>
         /// <seealso cref="TryCopyBitStringBytes(Asn1Tag,Span{byte},out int,out int)"/>
         public byte[] ReadBitString(Asn1Tag expectedTag, out int unusedBitCount)
         {
-            ReadOnlyMemory<byte> memory;
+            ReadOnlySpan<byte> span;
 
-            if (TryReadPrimitiveBitStringValue(expectedTag, out unusedBitCount, out memory))
+            if (TryReadPrimitiveBitStringValue(expectedTag, out unusedBitCount, out span))
             {
-                return memory.ToArray();
+                return span.ToArray();
             }
 
-            memory = PeekEncodedValue();
+            span = PeekEncodedValue();
 
             // Guaranteed long enough
-            byte[] rented = CryptoPool.Rent(memory.Length);
+            byte[] rented = CryptoPool.Rent(span.Length);
             int dataLength = 0;
 
             try
@@ -374,9 +294,9 @@ namespace System.Security.Cryptography.Asn1
         }
 
         private void ParsePrimitiveBitStringContents(
-            ReadOnlyMemory<byte> source,
+            ReadOnlySpan<byte> source,
             out int unusedBitCount,
-            out ReadOnlyMemory<byte> value,
+            out ReadOnlySpan<byte> value,
             out byte normalizedLastByte)
         {
             // T-REC-X.690-201508 sec 9.2
@@ -391,8 +311,7 @@ namespace System.Security.Cryptography.Asn1
                 throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
             }
 
-            ReadOnlySpan<byte> sourceSpan = source.Span;
-            unusedBitCount = sourceSpan[0];
+            unusedBitCount = source[0];
 
             // T-REC-X.690-201508 sec 8.6.2.2
             if (unusedBitCount > 7)
@@ -409,7 +328,7 @@ namespace System.Security.Cryptography.Asn1
                 }
 
                 Debug.Assert(unusedBitCount == 0);
-                value = ReadOnlyMemory<byte>.Empty;
+                value = ReadOnlySpan<byte>.Empty;
                 normalizedLastByte = 0;
                 return;
             }
@@ -419,7 +338,7 @@ namespace System.Security.Cryptography.Asn1
             // If 3 bits are "unused" then build a mask for them to check for 0.
             // -1 << 3 => 0b1111_1111 << 3 => 0b1111_1000
             int mask = -1 << unusedBitCount;
-            byte lastByte = sourceSpan[sourceSpan.Length - 1];
+            byte lastByte = source[source.Length - 1];
             byte maskedByte = (byte)(lastByte & mask);
 
             if (maskedByte != lastByte)
@@ -436,12 +355,12 @@ namespace System.Security.Cryptography.Asn1
         }
 
         private delegate void BitStringCopyAction(
-            ReadOnlyMemory<byte> value,
+            ReadOnlySpan<byte> value,
             byte normalizedLastByte,
             Span<byte> destination);
 
         private static void CopyBitStringValue(
-            ReadOnlyMemory<byte> value,
+            ReadOnlySpan<byte> value,
             byte normalizedLastByte,
             Span<byte> destination)
         {
@@ -450,12 +369,12 @@ namespace System.Security.Cryptography.Asn1
                 return;
             }
 
-            value.Span.CopyTo(destination);
+            value.CopyTo(destination);
             // Replace the last byte with the normalized answer.
             destination[value.Length - 1] = normalizedLastByte;
         }
 
-        private int CountConstructedBitString(ReadOnlyMemory<byte> source, bool isIndefinite)
+        private int CountConstructedBitString(ReadOnlySpan<byte> source, bool isIndefinite)
         {
             Span<byte> destination = Span<byte>.Empty;
 
@@ -469,7 +388,7 @@ namespace System.Security.Cryptography.Asn1
         }
 
         private void CopyConstructedBitString(
-            ReadOnlyMemory<byte> source,
+            ReadOnlySpan<byte> source,
             Span<byte> destination,
             bool isIndefinite,
             out int unusedBitCount,
@@ -488,7 +407,7 @@ namespace System.Security.Cryptography.Asn1
         }
 
         private int ProcessConstructedBitString(
-            ReadOnlyMemory<byte> source,
+            ReadOnlySpan<byte> source,
             Span<byte> destination,
             BitStringCopyAction? copyAction,
             bool isIndefinite,
@@ -499,13 +418,14 @@ namespace System.Security.Cryptography.Asn1
             bytesRead = 0;
             int lastSegmentLength = MaxCERSegmentSize;
 
-            AsnReader? tmpReader = new AsnReader(source, RuleSet);
-            Stack<(AsnReader, bool, int)>? readerStack = null;
+            ReadOnlySpan<byte> originalSpan = _data;
+            AsnValueReader tmpReader = OpenUnchecked(source, RuleSet);
+            Stack<(int Offset, int Length, bool Indefinite, int BytesRead)>? readerStack = null;
             int totalLength = 0;
             Asn1Tag tag = Asn1Tag.ConstructedBitString;
             Span<byte> curDest = destination;
 
-            do
+            while (true)
             {
                 while (tmpReader.HasData)
                 {
@@ -527,12 +447,12 @@ namespace System.Security.Cryptography.Asn1
                         }
 
                         Debug.Assert(length != null);
-                        ReadOnlyMemory<byte> encodedValue = Slice(tmpReader._data, headerLength, length.Value);
+                        ReadOnlySpan<byte> encodedValue = Slice(tmpReader._data, headerLength, length.Value);
 
                         ParsePrimitiveBitStringContents(
                             encodedValue,
                             out lastUnusedBitCount,
-                            out ReadOnlyMemory<byte> contents,
+                            out ReadOnlySpan<byte> contents,
                             out byte normalizedLastByte);
 
                         int localLen = headerLength + encodedValue.Length;
@@ -556,12 +476,12 @@ namespace System.Security.Cryptography.Asn1
 
                         if (readerStack?.Count > 0)
                         {
-                            (AsnReader topReader, bool wasIndefinite, int pushedBytesRead) = readerStack.Pop();
-                            topReader._data = topReader._data.Slice(bytesRead);
+                            (int topOffset, int topLength, bool wasIndefinite, int pushedBytesRead) = readerStack.Pop();
+                            ReadOnlySpan<byte> topSpan = originalSpan.Slice(topOffset, topLength);
+                            tmpReader._data = topSpan.Slice(bytesRead);
 
                             bytesRead += pushedBytesRead;
                             isIndefinite = wasIndefinite;
-                            tmpReader = topReader;
                         }
                         else
                         {
@@ -579,15 +499,18 @@ namespace System.Security.Cryptography.Asn1
 
                         if (readerStack == null)
                         {
-                            readerStack = new Stack<(AsnReader, bool, int)>();
+                            readerStack = new Stack<(int, int, bool, int)>();
                         }
 
-                        readerStack.Push((tmpReader, isIndefinite, bytesRead));
+                        if (!originalSpan.Overlaps(tmpReader._data, out int curOffset))
+                        {
+                            Debug.Fail("Non-overlapping data encountered...");
+                            throw new CryptographicException();
+                        }
 
-                        tmpReader = new AsnReader(
-                            Slice(tmpReader._data, headerLength, length),
-                            RuleSet);
+                        readerStack.Push((curOffset, tmpReader._data.Length, isIndefinite, bytesRead));
 
+                        tmpReader._data = Slice(tmpReader._data, headerLength, length);
                         bytesRead = headerLength;
                         isIndefinite = (length == null);
                     }
@@ -605,25 +528,23 @@ namespace System.Security.Cryptography.Asn1
 
                 if (readerStack?.Count > 0)
                 {
-                    (AsnReader topReader, bool wasIndefinite, int pushedBytesRead) = readerStack.Pop();
+                    (int topOffset, int topLength, bool wasIndefinite, int pushedBytesRead) = readerStack.Pop();
 
-                    tmpReader = topReader;
-                    tmpReader._data = tmpReader._data.Slice(bytesRead);
+                    ReadOnlySpan<byte> tmpSpan = originalSpan.Slice(topOffset, topLength);
+                    tmpReader._data = tmpSpan.Slice(bytesRead);
 
                     isIndefinite = wasIndefinite;
                     bytesRead += pushedBytesRead;
                 }
                 else
                 {
-                    tmpReader = null;
+                    return totalLength;
                 }
-            } while (tmpReader != null);
-
-            return totalLength;
+            }
         }
 
         private bool TryCopyConstructedBitStringValue(
-            ReadOnlyMemory<byte> source,
+            ReadOnlySpan<byte> source,
             Span<byte> dest,
             bool isIndefinite,
             out int unusedBitCount,
@@ -669,7 +590,7 @@ namespace System.Security.Cryptography.Asn1
             out int? contentsLength,
             out int headerLength,
             out int unusedBitCount,
-            out ReadOnlyMemory<byte> value,
+            out ReadOnlySpan<byte> value,
             out byte normalizedLastByte)
         {
             actualTag = ReadTagAndLength(out contentsLength, out headerLength);
@@ -683,13 +604,13 @@ namespace System.Security.Cryptography.Asn1
                 }
 
                 unusedBitCount = 0;
-                value = default(ReadOnlyMemory<byte>);
+                value = default;
                 normalizedLastByte = 0;
                 return false;
             }
 
             Debug.Assert(contentsLength.HasValue);
-            ReadOnlyMemory<byte> encodedValue = Slice(_data, headerLength, contentsLength.Value);
+            ReadOnlySpan<byte> encodedValue = Slice(_data, headerLength, contentsLength.Value);
 
             ParsePrimitiveBitStringContents(
                 encodedValue,
@@ -700,4 +621,299 @@ namespace System.Security.Cryptography.Asn1
             return true;
         }
     }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as a BIT STRING with tag UNIVERSAL 3, returning the contents
+        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        /// </summary>
+        /// <param name="unusedBitCount">
+        ///   On success, receives the number of bits in the last byte which were reported as
+        ///   "unused" by the writer.
+        /// </param>
+        /// <param name="value">
+        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
+        ///   corresponding to the value of the BIT STRING.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if the BIT STRING value had a primitive encoding,
+        ///   <c>false</c> and does not advance the reader if it had a constructed encoding.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="TryCopyBitStringBytes(Span{byte},out int,out int)"/>
+        public bool TryReadPrimitiveBitStringValue(out int unusedBitCount, out ReadOnlyMemory<byte> value)
+            => TryReadPrimitiveBitStringValue(Asn1Tag.PrimitiveBitString, out unusedBitCount, out value);
+
+        /// <summary>
+        ///   Reads the next value as a BIT STRING with a specified tag, returning the contents
+        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="unusedBitCount">
+        ///   On success, receives the number of bits in the last byte which were reported as
+        ///   "unused" by the writer.
+        /// </param>
+        /// <param name="value">
+        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
+        ///   corresponding to the value of the BIT STRING.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if the BIT STRING value had a primitive encoding,
+        ///   <c>false</c> and does not advance the reader if it had a constructed encoding.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        /// <seealso cref="TryCopyBitStringBytes(Asn1Tag,Span{byte},out int,out int)"/>
+        public bool TryReadPrimitiveBitStringValue(
+            Asn1Tag expectedTag,
+            out int unusedBitCount,
+            out ReadOnlyMemory<byte> value)
+        {
+            AsnValueReader reader = OpenValueReader();
+
+            if (reader.TryReadPrimitiveBitStringValue(expectedTag, out unusedBitCount, out ReadOnlySpan<byte> span))
+            {
+                value = AsnValueReader.Slice(_data, span);
+                reader.MatchSlice(ref _data);
+                return true;
+            }
+
+            value = default;
+            return false;
+        }
+
+        /// <summary>
+        ///   Reads the next value as a BIT STRING with tag UNIVERSAL 3, copying the value
+        ///   into a provided destination buffer.
+        /// </summary>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="unusedBitCount">
+        ///   On success, receives the number of bits in the last byte which were reported as
+        ///   "unused" by the writer.
+        /// </param>
+        /// <param name="bytesWritten">
+        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveBitStringValue(out int,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadBitString(out int)"/>
+        public bool TryCopyBitStringBytes(
+            Span<byte> destination,
+            out int unusedBitCount,
+            out int bytesWritten)
+        {
+            return TryCopyBitStringBytes(
+                Asn1Tag.PrimitiveBitString,
+                destination,
+                out unusedBitCount,
+                out bytesWritten);
+        }
+
+        /// <summary>
+        ///   Reads the next value as a BIT STRING with a specified tag, copying the value
+        ///   into a provided destination buffer.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="unusedBitCount">
+        ///   On success, receives the number of bits in the last byte which were reported as
+        ///   "unused" by the writer.
+        /// </param>
+        /// <param name="bytesWritten">
+        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveBitStringValue(Asn1Tag,out int,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadBitString(Asn1Tag,out int)"/>
+        public bool TryCopyBitStringBytes(
+            Asn1Tag expectedTag,
+            Span<byte> destination,
+            out int unusedBitCount,
+            out int bytesWritten)
+        {
+            AsnValueReader reader = OpenValueReader();
+
+            if (reader.TryCopyBitStringBytes(expectedTag, destination, out unusedBitCount, out bytesWritten))
+            {
+                reader.MatchSlice(ref _data);
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        ///   Reads the next value as a BIT STRING with tag UNIVERSAL 3, copying the value
+        ///   into a provided destination buffer.
+        /// </summary>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="unusedBitCount">
+        ///   On success, receives the number of bits in the last byte which were reported as
+        ///   "unused" by the writer.
+        /// </param>
+        /// <param name="bytesWritten">
+        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveBitStringValue(out int,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadBitString(out int)"/>
+        public bool TryCopyBitStringBytes(
+            ArraySegment<byte> destination,
+            out int unusedBitCount,
+            out int bytesWritten)
+        {
+            return TryCopyBitStringBytes(
+                Asn1Tag.PrimitiveBitString,
+                destination.AsSpan(),
+                out unusedBitCount,
+                out bytesWritten);
+        }
+
+        /// <summary>
+        ///   Reads the next value as a BIT STRING with a specified tag, copying the value
+        ///   into a provided destination buffer.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="unusedBitCount">
+        ///   On success, receives the number of bits in the last byte which were reported as
+        ///   "unused" by the writer.
+        /// </param>
+        /// <param name="bytesWritten">
+        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveBitStringValue(Asn1Tag,out int,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadBitString(Asn1Tag,out int)"/>
+        public bool TryCopyBitStringBytes(
+            Asn1Tag expectedTag,
+            ArraySegment<byte> destination,
+            out int unusedBitCount,
+            out int bytesWritten)
+        {
+            return TryCopyBitStringBytes(
+                expectedTag,
+                destination.AsSpan(),
+                out unusedBitCount,
+                out bytesWritten);
+        }
+
+        /// <summary>
+        ///   Reads the next value as a BIT STRING with tag UNIVERSAL 3, returning the value
+        ///   in a byte array.
+        /// </summary>
+        /// <param name="unusedBitCount">
+        ///   On success, receives the number of bits in the last byte which were reported as
+        ///   "unused" by the writer.
+        /// </param>
+        /// <returns>
+        ///   a copy of the value in a newly allocated, precisely sized, array.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveBitStringValue(out int,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryCopyBitStringBytes(Span{byte},out int,out int)"/>
+        public byte[] ReadBitString(out int unusedBitCount)
+        {
+            return ReadBitString(Asn1Tag.PrimitiveBitString, out unusedBitCount);
+        }
+
+        /// <summary>
+        ///   Reads the next value as a BIT STRING with tag UNIVERSAL 3, returning the value
+        ///   in a byte array.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="unusedBitCount">
+        ///   On success, receives the number of bits in the last byte which were reported as
+        ///   "unused" by the writer.
+        /// </param>
+        /// <returns>
+        ///   a copy of the value in a newly allocated, precisely sized, array.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveBitStringValue(Asn1Tag,out int,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryCopyBitStringBytes(Asn1Tag,Span{byte},out int,out int)"/>
+        public byte[] ReadBitString(Asn1Tag expectedTag, out int unusedBitCount)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            byte[] ret = valueReader.ReadBitString(expectedTag, out unusedBitCount);
+            valueReader.MatchSlice(ref _data);
+            return ret;
+        }
+    }
 }
index 31634ab..8743adf 100644 (file)
@@ -7,7 +7,7 @@ using System.Diagnostics;
 #nullable enable
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         /// <summary>
         ///   Reads the next value as a Boolean with tag UNIVERSAL 1.
@@ -49,7 +49,7 @@ namespace System.Security.Cryptography.Asn1
 
             Debug.Assert(length.HasValue);
             bool value = ReadBooleanValue(
-                Slice(_data, headerLength, length.Value).Span,
+                Slice(_data, headerLength, length.Value),
                 RuleSet);
 
             _data = _data.Slice(headerLength + length.Value);
@@ -83,4 +83,42 @@ namespace System.Security.Cryptography.Asn1
             return true;
         }
     }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as a Boolean with tag UNIVERSAL 1.
+        /// </summary>
+        /// <returns>The next value as a Boolean.</returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public bool ReadBoolean() => ReadBoolean(Asn1Tag.Boolean);
+
+        /// <summary>
+        ///   Reads the next value as a Boolean with a specified tag.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <returns>The next value as a Boolean.</returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public bool ReadBoolean(Asn1Tag expectedTag)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            bool ret = valueReader.ReadBoolean(expectedTag);
+            valueReader.MatchSlice(ref _data);
+            return ret;
+        }
+    }
 }
index d97071b..296e596 100644 (file)
@@ -7,11 +7,11 @@ using System.Runtime.InteropServices;
 
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         /// <summary>
         ///   Reads the next value as an Enumerated value with tag UNIVERSAL 10,
-        ///   returning the contents as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        ///   returning the contents as a <see cref="ReadOnlySpan{T}"/> over the original data.
         /// </summary>
         /// <returns>
         ///   The bytes of the Enumerated value, in signed big-endian form.
@@ -22,12 +22,12 @@ namespace System.Security.Cryptography.Asn1
         ///   the contents are not valid under the current encoding rules
         /// </exception>
         /// <seealso cref="ReadEnumeratedValue{TEnum}()"/>
-        public ReadOnlyMemory<byte> ReadEnumeratedBytes() =>
+        public ReadOnlySpan<byte> ReadEnumeratedBytes() =>
             ReadEnumeratedBytes(Asn1Tag.Enumerated);
 
         /// <summary>
         ///   Reads the next value as a Enumerated with a specified tag, returning the contents
-        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        ///   as a <see cref="ReadOnlySpan{T}"/> over the original data.
         /// </summary>
         /// <param name="expectedTag">The tag to check for before reading.</param>
         /// <returns>
@@ -45,10 +45,10 @@ namespace System.Security.Cryptography.Asn1
         ///   the method
         /// </exception>
         /// <seealso cref="ReadEnumeratedValue{TEnum}(Asn1Tag)"/>
-        public ReadOnlyMemory<byte> ReadEnumeratedBytes(Asn1Tag expectedTag)
+        public ReadOnlySpan<byte> ReadEnumeratedBytes(Asn1Tag expectedTag)
         {
             // T-REC-X.690-201508 sec 8.4 says the contents are the same as for integers.
-            ReadOnlyMemory<byte> contents =
+            ReadOnlySpan<byte> contents =
                 GetIntegerContents(expectedTag, UniversalTagNumber.Enumerated, out int headerLength);
 
             _data = _data.Slice(headerLength + contents.Length);
@@ -222,4 +222,180 @@ namespace System.Security.Cryptography.Asn1
             throw new CryptographicException();
         }
     }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as an Enumerated value with tag UNIVERSAL 10,
+        ///   returning the contents as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        /// </summary>
+        /// <returns>
+        ///   The bytes of the Enumerated value, in signed big-endian form.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="ReadEnumeratedValue{TEnum}()"/>
+        public ReadOnlyMemory<byte> ReadEnumeratedBytes() =>
+            ReadEnumeratedBytes(Asn1Tag.Enumerated);
+
+        /// <summary>
+        ///   Reads the next value as a Enumerated with a specified tag, returning the contents
+        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <returns>
+        ///   The bytes of the Enumerated value, in signed big-endian form.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        /// <seealso cref="ReadEnumeratedValue{TEnum}(Asn1Tag)"/>
+        public ReadOnlyMemory<byte> ReadEnumeratedBytes(Asn1Tag expectedTag)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            ReadOnlySpan<byte> bytes = valueReader.ReadEnumeratedBytes(expectedTag);
+            ReadOnlyMemory<byte> memory = AsnValueReader.Slice(_data, bytes);
+
+            valueReader.MatchSlice(ref _data);
+            return memory;
+        }
+
+        /// <summary>
+        ///   Reads the next value as an Enumerated value with tag UNIVERSAL 10, converting it to
+        ///   the non-[<see cref="FlagsAttribute"/>] enum specfied by <typeparamref name="TEnum"/>.
+        /// </summary>
+        /// <typeparam name="TEnum">Destination enum type</typeparam>
+        /// <returns>
+        ///   the Enumerated value converted to a <typeparamref name="TEnum"/>.
+        /// </returns>
+        /// <remarks>
+        ///   This method does not validate that the return value is defined within
+        ///   <typeparamref name="TEnum"/>.
+        /// </remarks>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the encoded value is too big to fit in a <typeparamref name="TEnum"/> value
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <typeparamref name="TEnum"/> is not an enum type --OR--
+        ///   <typeparamref name="TEnum"/> was declared with <see cref="FlagsAttribute"/>
+        /// </exception>
+        /// <seealso cref="ReadEnumeratedValue{TEnum}(Asn1Tag)"/>
+        public TEnum ReadEnumeratedValue<TEnum>() where TEnum : struct
+        {
+            Type tEnum = typeof(TEnum);
+
+            return (TEnum)Enum.ToObject(tEnum, ReadEnumeratedValue(tEnum));
+        }
+
+        /// <summary>
+        ///   Reads the next value as an Enumerated with tag UNIVERSAL 10, converting it to the
+        ///   non-[<see cref="FlagsAttribute"/>] enum specfied by <typeparamref name="TEnum"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <typeparam name="TEnum">Destination enum type</typeparam>
+        /// <returns>
+        ///   the Enumerated value converted to a <typeparamref name="TEnum"/>.
+        /// </returns>
+        /// <remarks>
+        ///   This method does not validate that the return value is defined within
+        ///   <typeparamref name="TEnum"/>.
+        /// </remarks>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the encoded value is too big to fit in a <typeparamref name="TEnum"/> value
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <typeparamref name="TEnum"/> is not an enum type --OR--
+        ///   <typeparamref name="TEnum"/> was declared with <see cref="FlagsAttribute"/>
+        ///   --OR--
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public TEnum ReadEnumeratedValue<TEnum>(Asn1Tag expectedTag) where TEnum : struct
+        {
+            Type tEnum = typeof(TEnum);
+
+            return (TEnum)Enum.ToObject(tEnum, ReadEnumeratedValue(expectedTag, tEnum));
+        }
+
+        /// <summary>
+        ///   Reads the next value as an Enumerated value with tag UNIVERSAL 10, converting it to
+        ///   the non-[<see cref="FlagsAttribute"/>] enum specfied by <paramref name="tEnum"/>.
+        /// </summary>
+        /// <param name="tEnum">Type object representing the destination type.</param>
+        /// <returns>
+        ///   the Enumerated value converted to a <paramref name="tEnum"/>.
+        /// </returns>
+        /// <remarks>
+        ///   This method does not validate that the return value is defined within
+        ///   <paramref name="tEnum"/>.
+        /// </remarks>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the encoded value is too big to fit in a <paramref name="tEnum"/> value
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="tEnum"/> is not an enum type --OR--
+        ///   <paramref name="tEnum"/> was declared with <see cref="FlagsAttribute"/>
+        /// </exception>
+        /// <seealso cref="ReadEnumeratedValue(Asn1Tag, Type)"/>
+        public Enum ReadEnumeratedValue(Type tEnum) =>
+            ReadEnumeratedValue(Asn1Tag.Enumerated, tEnum);
+
+        /// <summary>
+        ///   Reads the next value as an Enumerated with tag UNIVERSAL 10, converting it to the
+        ///   non-[<see cref="FlagsAttribute"/>] enum specfied by <paramref name="tEnum"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="tEnum">Type object representing the destination type.</param>
+        /// <returns>
+        ///   the Enumerated value converted to a <paramref name="tEnum"/>.
+        /// </returns>
+        /// <remarks>
+        ///   This method does not validate that the return value is defined within
+        ///   <paramref name="tEnum"/>.
+        /// </remarks>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the encoded value is too big to fit in a <paramref name="tEnum"/> value
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="tEnum"/> is not an enum type --OR--
+        ///   <paramref name="tEnum"/> was declared with <see cref="FlagsAttribute"/>
+        ///   --OR--
+        ///   <paramref name="tEnum"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="tEnum"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public Enum ReadEnumeratedValue(Asn1Tag expectedTag, Type tEnum)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            Enum ret = valueReader.ReadEnumeratedValue(expectedTag, tEnum);
+            valueReader.MatchSlice(ref _data);
+            return ret;
+        }
+    }
 }
index f58eeef..9c55f21 100644 (file)
@@ -9,7 +9,7 @@ using System.Diagnostics;
 #nullable enable
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         /// <summary>
         ///   Reads the next value as a GeneralizedTime with tag UNIVERSAL 24.
@@ -56,10 +56,16 @@ namespace System.Security.Cryptography.Asn1
         public DateTimeOffset ReadGeneralizedTime(Asn1Tag expectedTag, bool disallowFractions = false)
         {
             byte[]? rented = null;
+            Span<byte> tmpSpace;
 
-            // An X.509 time is 15 characters (yyyyMMddHHmmssZ), beyond that is fractions (no limit) or
-            // BER specified offset.
-            Span<byte> tmpSpace = stackalloc byte[64];
+            unsafe
+            {
+                // An X.509 time is 15 characters (yyyyMMddHHmmssZ), beyond that is fractions (no limit) or
+                // BER specified offset.
+                const int StackBufSize = 64;
+                byte* stackBuf = stackalloc byte[StackBufSize];
+                tmpSpace = new Span<byte>(stackBuf, StackBufSize);
+            }
 
             ReadOnlySpan<byte> contents = GetOctetStringContents(
                 expectedTag,
@@ -406,4 +412,57 @@ namespace System.Security.Cryptography.Asn1
             }
         }
     }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as a GeneralizedTime with tag UNIVERSAL 24.
+        /// </summary>
+        /// <param name="disallowFractions">
+        ///   <c>true</c> to cause a <see cref="CryptographicException"/> to be thrown if a
+        ///   fractional second is encountered, such as the restriction on the PKCS#7 Signing
+        ///   Time attribute.
+        /// </param>
+        /// <returns>
+        ///   a DateTimeOffset representing the value encoded in the GeneralizedTime.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public DateTimeOffset ReadGeneralizedTime(bool disallowFractions = false) =>
+            ReadGeneralizedTime(Asn1Tag.GeneralizedTime, disallowFractions);
+
+        /// <summary>
+        ///   Reads the next value as a GeneralizedTime with a specified tag.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="disallowFractions">
+        ///   <c>true</c> to cause a <see cref="CryptographicException"/> to be thrown if a
+        ///   fractional second is encountered, such as the restriction on the PKCS#7 Signing
+        ///   Time attribute.
+        /// </param>
+        /// <returns>
+        ///   a DateTimeOffset representing the value encoded in the GeneralizedTime.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public DateTimeOffset ReadGeneralizedTime(Asn1Tag expectedTag, bool disallowFractions = false)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            DateTimeOffset ret = valueReader.ReadGeneralizedTime(expectedTag, disallowFractions);
+            valueReader.MatchSlice(ref _data);
+            return ret;
+        }
+    }
 }
index fc8a536..3939428 100644 (file)
@@ -8,11 +8,11 @@ using System.Numerics;
 #nullable enable
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         /// <summary>
         ///   Reads the next value as an Integer with tag UNIVERSAL 2, returning the contents
-        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        ///   as a <see cref="ReadOnlySpan{T}"/> over the original data.
         /// </summary>
         /// <returns>
         ///   The bytes of the Integer value, in signed big-endian form.
@@ -22,12 +22,12 @@ namespace System.Security.Cryptography.Asn1
         ///   the length encoding is not valid under the current encoding rules --OR--
         ///   the contents are not valid under the current encoding rules
         /// </exception>
-        public ReadOnlyMemory<byte> ReadIntegerBytes() =>
+        public ReadOnlySpan<byte> ReadIntegerBytes() =>
             ReadIntegerBytes(Asn1Tag.Integer);
 
         /// <summary>
         ///   Reads the next value as a Integer with a specified tag, returning the contents
-        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        ///   as a <see cref="ReadOnlySpan{T}"/> over the original data.
         /// </summary>
         /// <param name="expectedTag">The tag to check for before reading.</param>
         /// <returns>
@@ -44,9 +44,9 @@ namespace System.Security.Cryptography.Asn1
         ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
         ///   the method
         /// </exception>
-        public ReadOnlyMemory<byte> ReadIntegerBytes(Asn1Tag expectedTag)
+        public ReadOnlySpan<byte> ReadIntegerBytes(Asn1Tag expectedTag)
         {
-            ReadOnlyMemory<byte> contents =
+            ReadOnlySpan<byte> contents =
                 GetIntegerContents(expectedTag, UniversalTagNumber.Integer, out int headerLength);
 
             _data = _data.Slice(headerLength + contents.Length);
@@ -88,7 +88,7 @@ namespace System.Security.Cryptography.Asn1
         /// </exception>
         public BigInteger ReadInteger(Asn1Tag expectedTag)
         {
-            ReadOnlyMemory<byte> contents =
+            ReadOnlySpan<byte> contents =
                 GetIntegerContents(expectedTag, UniversalTagNumber.Integer, out int headerLength);
 
             // TODO: Split this for netcoreapp/netstandard to use the Big-Endian BigInteger parsing
@@ -97,7 +97,7 @@ namespace System.Security.Cryptography.Asn1
 
             try
             {
-                byte fill = (contents.Span[0] & 0x80) == 0 ? (byte)0 : (byte)0xFF;
+                byte fill = (contents[0] & 0x80) == 0 ? (byte)0 : (byte)0xFF;
                 // Fill the unused portions of tmp with positive or negative padding.
                 new Span<byte>(tmp, contents.Length, tmp.Length - contents.Length).Fill(fill);
                 contents.CopyTo(tmp);
@@ -550,7 +550,7 @@ namespace System.Security.Cryptography.Asn1
             return false;
         }
 
-        private ReadOnlyMemory<byte> GetIntegerContents(
+        private ReadOnlySpan<byte> GetIntegerContents(
             Asn1Tag expectedTag,
             UniversalTagNumber tagNumber,
             out int headerLength)
@@ -565,13 +565,12 @@ namespace System.Security.Cryptography.Asn1
             }
 
             // Slice first so that an out of bounds value triggers a CryptographicException.
-            ReadOnlyMemory<byte> contents = Slice(_data, headerLength, length!.Value);
-            ReadOnlySpan<byte> contentSpan = contents.Span;
+            ReadOnlySpan<byte> contents = Slice(_data, headerLength, length!.Value);
 
             // T-REC-X.690-201508 sec 8.3.2
             if (contents.Length > 1)
             {
-                ushort bigEndianValue = (ushort)(contentSpan[0] << 8 | contentSpan[1]);
+                ushort bigEndianValue = (ushort)(contents[0] << 8 | contents[1]);
                 const ushort RedundancyMask = 0b1111_1111_1000_0000;
                 ushort masked = (ushort)(bigEndianValue & RedundancyMask);
 
@@ -585,7 +584,7 @@ namespace System.Security.Cryptography.Asn1
             return contents;
         }
 
-        private bool TryReadSignedInteger(
+        internal bool TryReadSignedInteger(
             int sizeLimit,
             Asn1Tag expectedTag,
             UniversalTagNumber tagNumber,
@@ -593,7 +592,7 @@ namespace System.Security.Cryptography.Asn1
         {
             Debug.Assert(sizeLimit <= sizeof(long));
 
-            ReadOnlyMemory<byte> contents = GetIntegerContents(expectedTag, tagNumber, out int headerLength);
+            ReadOnlySpan<byte> contents = GetIntegerContents(expectedTag, tagNumber, out int headerLength);
 
             if (contents.Length > sizeLimit)
             {
@@ -601,15 +600,13 @@ namespace System.Security.Cryptography.Asn1
                 return false;
             }
 
-            ReadOnlySpan<byte> contentSpan = contents.Span;
-
-            bool isNegative = (contentSpan[0] & 0x80) != 0;
+            bool isNegative = (contents[0] & 0x80) != 0;
             long accum = isNegative ? -1 : 0;
 
             for (int i = 0; i < contents.Length; i++)
             {
                 accum <<= 8;
-                accum |= contentSpan[i];
+                accum |= contents[i];
             }
 
             _data = _data.Slice(headerLength + contents.Length);
@@ -617,7 +614,7 @@ namespace System.Security.Cryptography.Asn1
             return true;
         }
 
-        private bool TryReadUnsignedInteger(
+        internal bool TryReadUnsignedInteger(
             int sizeLimit,
             Asn1Tag expectedTag,
             UniversalTagNumber tagNumber,
@@ -625,11 +622,10 @@ namespace System.Security.Cryptography.Asn1
         {
             Debug.Assert(sizeLimit <= sizeof(ulong));
 
-            ReadOnlyMemory<byte> contents = GetIntegerContents(expectedTag, tagNumber, out int headerLength);
-            ReadOnlySpan<byte> contentSpan = contents.Span;
+            ReadOnlySpan<byte> contents = GetIntegerContents(expectedTag, tagNumber, out int headerLength);
             int contentLength = contents.Length;
 
-            bool isNegative = (contentSpan[0] & 0x80) != 0;
+            bool isNegative = (contents[0] & 0x80) != 0;
 
             if (isNegative)
             {
@@ -638,12 +634,12 @@ namespace System.Security.Cryptography.Asn1
             }
 
             // Ignore any padding zeros.
-            if (contentSpan.Length > 1 && contentSpan[0] == 0)
+            if (contents.Length > 1 && contents[0] == 0)
             {
-                contentSpan = contentSpan.Slice(1);
+                contents = contents.Slice(1);
             }
 
-            if (contentSpan.Length > sizeLimit)
+            if (contents.Length > sizeLimit)
             {
                 value = 0;
                 return false;
@@ -651,10 +647,10 @@ namespace System.Security.Cryptography.Asn1
 
             ulong accum = 0;
 
-            for (int i = 0; i < contentSpan.Length; i++)
+            for (int i = 0; i < contents.Length; i++)
             {
                 accum <<= 8;
-                accum |= contentSpan[i];
+                accum |= contents[i];
             }
 
             _data = _data.Slice(headerLength + contentLength);
@@ -662,4 +658,560 @@ namespace System.Security.Cryptography.Asn1
             return true;
         }
     }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as an Integer with tag UNIVERSAL 2, returning the contents
+        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        /// </summary>
+        /// <returns>
+        ///   The bytes of the Integer value, in signed big-endian form.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public ReadOnlyMemory<byte> ReadIntegerBytes() =>
+            ReadIntegerBytes(Asn1Tag.Integer);
+
+        /// <summary>
+        ///   Reads the next value as a Integer with a specified tag, returning the contents
+        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <returns>
+        ///   The bytes of the Integer value, in signed big-endian form.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public ReadOnlyMemory<byte> ReadIntegerBytes(Asn1Tag expectedTag)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            ReadOnlySpan<byte> bytes = valueReader.ReadIntegerBytes(expectedTag);
+            ReadOnlyMemory<byte> memory = AsnValueReader.Slice(_data, bytes);
+
+            valueReader.MatchSlice(ref _data);
+            return memory;
+        }
+
+        /// <summary>
+        ///   Reads the next value as an Integer with tag UNIVERSAL 2, returning the contents
+        ///   as a <see cref="BigInteger"/>.
+        /// </summary>
+        /// <returns>
+        ///   The bytes of the Integer value, in signed big-endian form.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public BigInteger ReadInteger() => ReadInteger(Asn1Tag.Integer);
+
+        /// <summary>
+        ///   Reads the next value as a Integer with a specified tag, returning the contents
+        ///   as a <see cref="BigInteger"/> over the original data.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <returns>
+        ///   The bytes of the Integer value, in signed big-endian form.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public BigInteger ReadInteger(Asn1Tag expectedTag)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            BigInteger ret = valueReader.ReadInteger(expectedTag);
+            valueReader.MatchSlice(ref _data);
+            return ret;
+        }
+
+        /// <summary>
+        ///   Reads the next value as an Integer with tag UNIVERSAL 2, interpreting the contents
+        ///   as an <see cref="int"/>.
+        /// </summary>
+        /// <param name="value">
+        ///   On success, receives the <see cref="int"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="int.MinValue"/> and <see cref="int.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public bool TryReadInt32(out int value) =>
+            TryReadInt32(Asn1Tag.Integer, out value);
+
+        /// <summary>
+        ///   Reads the next value as a Integer with a specified tag, interpreting the contents
+        ///   as an <see cref="int"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="value">
+        ///   On success, receives the <see cref="int"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="int.MinValue"/> and <see cref="int.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public bool TryReadInt32(Asn1Tag expectedTag, out int value)
+        {
+            if (TryReadSignedInteger(sizeof(int), expectedTag, UniversalTagNumber.Integer, out long longValue))
+            {
+                value = (int)longValue;
+                return true;
+            }
+
+            value = 0;
+            return false;
+        }
+
+        /// <summary>
+        ///   Reads the next value as an Integer with tag UNIVERSAL 2, interpreting the contents
+        ///   as a <see cref="uint"/>.
+        /// </summary>
+        /// <param name="value">
+        ///   On success, receives the <see cref="uint"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="uint.MinValue"/> and <see cref="uint.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public bool TryReadUInt32(out uint value) =>
+            TryReadUInt32(Asn1Tag.Integer, out value);
+
+        /// <summary>
+        ///   Reads the next value as a Integer with a specified tag, interpreting the contents
+        ///   as a <see cref="uint"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="value">
+        ///   On success, receives the <see cref="uint"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="uint.MinValue"/> and <see cref="uint.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public bool TryReadUInt32(Asn1Tag expectedTag, out uint value)
+        {
+            if (TryReadUnsignedInteger(sizeof(uint), expectedTag, UniversalTagNumber.Integer, out ulong ulongValue))
+            {
+                value = (uint)ulongValue;
+                return true;
+            }
+
+            value = 0;
+            return false;
+        }
+
+        /// <summary>
+        ///   Reads the next value as an Integer with tag UNIVERSAL 2, interpreting the contents
+        ///   as a <see cref="long"/>.
+        /// </summary>
+        /// <param name="value">
+        ///   On success, receives the <see cref="long"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="long.MinValue"/> and <see cref="long.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public bool TryReadInt64(out long value) =>
+            TryReadInt64(Asn1Tag.Integer, out value);
+
+        /// <summary>
+        ///   Reads the next value as a Integer with a specified tag, interpreting the contents
+        ///   as an <see cref="long"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="value">
+        ///   On success, receives the <see cref="long"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="long.MinValue"/> and <see cref="long.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public bool TryReadInt64(Asn1Tag expectedTag, out long value)
+        {
+            return TryReadSignedInteger(sizeof(long), expectedTag, UniversalTagNumber.Integer, out value);
+        }
+
+        /// <summary>
+        ///   Reads the next value as an Integer with tag UNIVERSAL 2, interpreting the contents
+        ///   as a <see cref="ulong"/>.
+        /// </summary>
+        /// <param name="value">
+        ///   On success, receives the <see cref="ulong"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="ulong.MinValue"/> and <see cref="ulong.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public bool TryReadUInt64(out ulong value) =>
+            TryReadUInt64(Asn1Tag.Integer, out value);
+
+        /// <summary>
+        ///   Reads the next value as a Integer with a specified tag, interpreting the contents
+        ///   as a <see cref="ulong"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="value">
+        ///   On success, receives the <see cref="ulong"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="ulong.MinValue"/> and <see cref="ulong.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public bool TryReadUInt64(Asn1Tag expectedTag, out ulong value)
+        {
+            return TryReadUnsignedInteger(sizeof(ulong), expectedTag, UniversalTagNumber.Integer, out value);
+        }
+
+        /// <summary>
+        ///   Reads the next value as an Integer with tag UNIVERSAL 2, interpreting the contents
+        ///   as a <see cref="short"/>.
+        /// </summary>
+        /// <param name="value">
+        ///   On success, receives the <see cref="short"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="short.MinValue"/> and <see cref="short.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public bool TryReadInt16(out short value) =>
+            TryReadInt16(Asn1Tag.Integer, out value);
+
+        /// <summary>
+        ///   Reads the next value as a Integer with a specified tag, interpreting the contents
+        ///   as an <see cref="short"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="value">
+        ///   On success, receives the <see cref="short"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="short.MinValue"/> and <see cref="short.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public bool TryReadInt16(Asn1Tag expectedTag, out short value)
+        {
+            if (TryReadSignedInteger(sizeof(short), expectedTag, UniversalTagNumber.Integer, out long longValue))
+            {
+                value = (short)longValue;
+                return true;
+            }
+
+            value = 0;
+            return false;
+        }
+
+        /// <summary>
+        ///   Reads the next value as an Integer with tag UNIVERSAL 2, interpreting the contents
+        ///   as a <see cref="ushort"/>.
+        /// </summary>
+        /// <param name="value">
+        ///   On success, receives the <see cref="ushort"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="ushort.MinValue"/> and <see cref="ushort.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public bool TryReadUInt16(out ushort value) =>
+            TryReadUInt16(Asn1Tag.Integer, out value);
+
+        /// <summary>
+        ///   Reads the next value as a Integer with a specified tag, interpreting the contents
+        ///   as a <see cref="ushort"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="value">
+        ///   On success, receives the <see cref="ushort"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="ushort.MinValue"/> and <see cref="ushort.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public bool TryReadUInt16(Asn1Tag expectedTag, out ushort value)
+        {
+            if (TryReadUnsignedInteger(sizeof(ushort), expectedTag, UniversalTagNumber.Integer, out ulong ulongValue))
+            {
+                value = (ushort)ulongValue;
+                return true;
+            }
+
+            value = 0;
+            return false;
+        }
+
+        /// <summary>
+        ///   Reads the next value as an Integer with tag UNIVERSAL 2, interpreting the contents
+        ///   as an <see cref="sbyte"/>.
+        /// </summary>
+        /// <param name="value">
+        ///   On success, receives the <see cref="sbyte"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="sbyte.MinValue"/> and <see cref="sbyte.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public bool TryReadInt8(out sbyte value) =>
+            TryReadInt8(Asn1Tag.Integer, out value);
+
+        /// <summary>
+        ///   Reads the next value as a Integer with a specified tag, interpreting the contents
+        ///   as an <see cref="sbyte"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="value">
+        ///   On success, receives the <see cref="sbyte"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="sbyte.MinValue"/> and <see cref="sbyte.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the Integer value is not valid
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public bool TryReadInt8(Asn1Tag expectedTag, out sbyte value)
+        {
+            if (TryReadSignedInteger(sizeof(sbyte), expectedTag, UniversalTagNumber.Integer, out long longValue))
+            {
+                value = (sbyte)longValue;
+                return true;
+            }
+
+            value = 0;
+            return false;
+        }
+
+        /// <summary>
+        ///   Reads the next value as an Integer with tag UNIVERSAL 2, interpreting the contents
+        ///   as a <see cref="byte"/>.
+        /// </summary>
+        /// <param name="value">
+        ///   On success, receives the <see cref="byte"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="byte.MinValue"/> and <see cref="byte.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public bool TryReadUInt8(out byte value) =>
+            TryReadUInt8(Asn1Tag.Integer, out value);
+
+        /// <summary>
+        ///   Reads the next value as a Integer with a specified tag, interpreting the contents
+        ///   as a <see cref="byte"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="value">
+        ///   On success, receives the <see cref="byte"/> value represented
+        /// </param>
+        /// <returns>
+        ///   <c>false</c> and does not advance the reader if the value is not between
+        ///   <see cref="byte.MinValue"/> and <see cref="byte.MaxValue"/>, inclusive; otherwise
+        ///   <c>true</c> is returned and the reader advances.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public bool TryReadUInt8(Asn1Tag expectedTag, out byte value)
+        {
+            if (TryReadUnsignedInteger(sizeof(byte), expectedTag, UniversalTagNumber.Integer, out ulong ulongValue))
+            {
+                value = (byte)ulongValue;
+                return true;
+            }
+
+            value = 0;
+            return false;
+        }
+
+        private bool TryReadSignedInteger(
+            int sizeLimit,
+            Asn1Tag expectedTag,
+            UniversalTagNumber tagNumber,
+            out long value)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+
+            if (valueReader.TryReadSignedInteger(sizeLimit, expectedTag, tagNumber, out value))
+            {
+                valueReader.MatchSlice(ref _data);
+                return true;
+            }
+
+            return false;
+        }
+
+        private bool TryReadUnsignedInteger(
+            int sizeLimit,
+            Asn1Tag expectedTag,
+            UniversalTagNumber tagNumber,
+            out ulong value)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+
+            if (valueReader.TryReadUnsignedInteger(sizeLimit, expectedTag, tagNumber, out value))
+            {
+                valueReader.MatchSlice(ref _data);
+                return true;
+            }
+
+            return false;
+        }
+    }
 }
index 290ab7e..d972df2 100644 (file)
@@ -7,7 +7,7 @@ using System.Runtime.InteropServices;
 
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         /// <summary>
         ///   Reads the next value as a NamedBitList with tag UNIVERSAL 3, converting it to the
@@ -165,8 +165,14 @@ namespace System.Security.Cryptography.Asn1
             }
 
             int sizeLimit = Marshal.SizeOf(backingType);
-            Span<byte> stackSpan = stackalloc byte[sizeLimit];
-            ReadOnlyMemory<byte> saveData = _data;
+            ReadOnlySpan<byte> saveData = _data;
+            Span<byte> stackSpan;
+
+            unsafe
+            {
+                byte* stackPtr = stackalloc byte[sizeLimit];
+                stackSpan = new Span<byte>(stackPtr, sizeLimit);
+            }
 
             // If TryCopyBitStringBytes succeeds but anything else fails _data will have moved,
             // so if anything throws here just move _data back to what it was.
@@ -265,4 +271,157 @@ namespace System.Security.Cryptography.Asn1
             return accum;
         }
     }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as a NamedBitList with tag UNIVERSAL 3, converting it to the
+        ///   [<see cref="FlagsAttribute"/>] enum specfied by <typeparamref name="TFlagsEnum"/>.
+        /// </summary>
+        /// <typeparam name="TFlagsEnum">Destination enum type</typeparam>
+        /// <returns>
+        ///   the NamedBitList value converted to a <typeparamref name="TFlagsEnum"/>.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the encoded value is too big to fit in a <typeparamref name="TFlagsEnum"/> value
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <typeparamref name="TFlagsEnum"/> is not an enum type --OR--
+        ///   <typeparamref name="TFlagsEnum"/> was not declared with <see cref="FlagsAttribute"/>
+        /// </exception>
+        /// <seealso cref="ReadNamedBitListValue{TFlagsEnum}(Asn1Tag)"/>
+        public TFlagsEnum ReadNamedBitListValue<TFlagsEnum>() where TFlagsEnum : struct =>
+            ReadNamedBitListValue<TFlagsEnum>(Asn1Tag.PrimitiveBitString);
+
+        /// <summary>
+        ///   Reads the next value as a NamedBitList with tag UNIVERSAL 3, converting it to the
+        ///   [<see cref="FlagsAttribute"/>] enum specfied by <typeparamref name="TFlagsEnum"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <typeparam name="TFlagsEnum">Destination enum type</typeparam>
+        /// <returns>
+        ///   the NamedBitList value converted to a <typeparamref name="TFlagsEnum"/>.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the encoded value is too big to fit in a <typeparamref name="TFlagsEnum"/> value
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <typeparamref name="TFlagsEnum"/> is not an enum type --OR--
+        ///   <typeparamref name="TFlagsEnum"/> was not declared with <see cref="FlagsAttribute"/>
+        ///   --OR--
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        /// <remarks>
+        ///   The bit alignment performed by this method is to interpret the most significant bit
+        ///   in the first byte of the value as the least significant bit in <typeparamref name="TFlagsEnum"/>,
+        ///   with bits increasing in value until the least significant bit of the first byte, proceeding
+        ///   with the most significant bit of the second byte, and so on. Under this scheme, the following
+        ///   ASN.1 type declaration and C# enumeration can be used together:
+        ///
+        ///   <code>
+        ///     KeyUsage ::= BIT STRING {
+        ///       digitalSignature   (0),
+        ///       nonRepudiation     (1),
+        ///       keyEncipherment    (2),
+        ///       dataEncipherment   (3),
+        ///       keyAgreement       (4),
+        ///       keyCertSign        (5),
+        ///       cRLSign            (6),
+        ///       encipherOnly       (7),
+        ///       decipherOnly       (8) }
+        ///   </code>
+        ///
+        ///   <code>
+        ///     [Flags]
+        ///     enum KeyUsage
+        ///     {
+        ///         None              = 0,
+        ///         DigitalSignature  = 1 &lt;&lt; (0),
+        ///         NonRepudiation    = 1 &lt;&lt; (1),
+        ///         KeyEncipherment   = 1 &lt;&lt; (2),
+        ///         DataEncipherment  = 1 &lt;&lt; (3),
+        ///         KeyAgreement      = 1 &lt;&lt; (4),
+        ///         KeyCertSign       = 1 &lt;&lt; (5),
+        ///         CrlSign           = 1 &lt;&lt; (6),
+        ///         EncipherOnly      = 1 &lt;&lt; (7),
+        ///         DecipherOnly      = 1 &lt;&lt; (8),
+        ///     }
+        ///   </code>
+        ///
+        ///   Note that while the example here uses the KeyUsage NamedBitList from
+        ///   <a href="https://tools.ietf.org/html/rfc3280#section-4.2.1.3">RFC 3280 (4.2.1.3)</a>,
+        ///   the example enum uses values thar are different from
+        ///   System.Security.Cryptography.X509Certificates.X509KeyUsageFlags.
+        /// </remarks>
+        public TFlagsEnum ReadNamedBitListValue<TFlagsEnum>(Asn1Tag expectedTag) where TFlagsEnum : struct
+        {
+            Type tFlagsEnum = typeof(TFlagsEnum);
+
+            return (TFlagsEnum)Enum.ToObject(tFlagsEnum, ReadNamedBitListValue(expectedTag, tFlagsEnum));
+        }
+
+        /// <summary>
+        ///   Reads the next value as a NamedBitList with tag UNIVERSAL 3, converting it to the
+        ///   [<see cref="FlagsAttribute"/>] enum specfied by <paramref name="tFlagsEnum"/>.
+        /// </summary>
+        /// <param name="tFlagsEnum">Type object representing the destination type.</param>
+        /// <returns>
+        ///   the NamedBitList value converted to a <paramref name="tFlagsEnum"/>.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the encoded value is too big to fit in a <paramref name="tFlagsEnum"/> value
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="tFlagsEnum"/> is not an enum type --OR--
+        ///   <paramref name="tFlagsEnum"/> was not declared with <see cref="FlagsAttribute"/>
+        /// </exception>
+        /// <seealso cref="ReadNamedBitListValue{TFlagsEnum}(Asn1Tag)"/>
+        public Enum ReadNamedBitListValue(Type tFlagsEnum) =>
+            ReadNamedBitListValue(Asn1Tag.PrimitiveBitString, tFlagsEnum);
+
+        /// <summary>
+        ///   Reads the next value as a NamedBitList with tag UNIVERSAL 3, converting it to the
+        ///   [<see cref="FlagsAttribute"/>] enum specfied by <paramref name="tFlagsEnum"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="tFlagsEnum">Type object representing the destination type.</param>
+        /// <returns>
+        ///   the NamedBitList value converted to a <paramref name="tFlagsEnum"/>.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR---
+        ///   the encoded value is too big to fit in a <paramref name="tFlagsEnum"/> value
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="tFlagsEnum"/> is not an enum type --OR--
+        ///   <paramref name="tFlagsEnum"/> was not declared with <see cref="FlagsAttribute"/>
+        ///   --OR--
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        /// <seealso cref="ReadNamedBitListValue{TFlagsEnum}(Asn1Tag)"/>
+        public Enum ReadNamedBitListValue(Asn1Tag expectedTag, Type tFlagsEnum)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            Enum ret = valueReader.ReadNamedBitListValue(expectedTag, tFlagsEnum);
+            valueReader.MatchSlice(ref _data);
+            return ret;
+        }
+    }
 }
index 15f7b3b..c7f781d 100644 (file)
@@ -4,7 +4,7 @@
 
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         /// <summary>
         ///   Reads the next value as a NULL with tag UNIVERSAL 5.
@@ -46,4 +46,39 @@ namespace System.Security.Cryptography.Asn1
             _data = _data.Slice(headerLength);
         }
     }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as a NULL with tag UNIVERSAL 5.
+        /// </summary>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public void ReadNull() => ReadNull(Asn1Tag.Null);
+
+        /// <summary>
+        ///   Reads the next value as a NULL with a specified tag.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public void ReadNull(Asn1Tag expectedTag)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            valueReader.ReadNull(expectedTag);
+            valueReader.MatchSlice(ref _data);
+        }
+    }
 }
index 27a9cb9..4b3756c 100644 (file)
@@ -9,7 +9,7 @@ using System.Diagnostics;
 #nullable enable
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         /// <summary>
         ///   Reads the next value as an OCTET STRING with tag UNIVERSAL 4, copying the value
@@ -29,7 +29,7 @@ namespace System.Security.Cryptography.Asn1
         ///   the length encoding is not valid under the current encoding rules --OR--
         ///   the contents are not valid under the current encoding rules
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveOctetStringBytes(out ReadOnlySpan{byte})"/>
         /// <seealso cref="ReadOctetString()"/>
         public bool TryCopyOctetStringBytes(
             Span<byte> destination,
@@ -66,7 +66,7 @@ namespace System.Security.Cryptography.Asn1
         ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
         ///   the method
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveOctetStringBytes(Asn1Tag,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveOctetStringBytes(Asn1Tag,out ReadOnlySpan{byte})"/>
         /// <seealso cref="ReadOctetString(Asn1Tag)"/>
         public bool TryCopyOctetStringBytes(
             Asn1Tag expectedTag,
@@ -78,7 +78,7 @@ namespace System.Security.Cryptography.Asn1
                 out Asn1Tag actualTag,
                 out int? contentLength,
                 out int headerLength,
-                out ReadOnlyMemory<byte> contents))
+                out ReadOnlySpan<byte> contents))
             {
                 if (contents.Length > destination.Length)
                 {
@@ -86,7 +86,7 @@ namespace System.Security.Cryptography.Asn1
                     return false;
                 }
 
-                contents.Span.CopyTo(destination);
+                contents.CopyTo(destination);
                 bytesWritten = contents.Length;
                 _data = _data.Slice(headerLength + contents.Length);
                 return true;
@@ -110,74 +110,6 @@ namespace System.Security.Cryptography.Asn1
         }
 
         /// <summary>
-        ///   Reads the next value as an OCTET STRING with tag UNIVERSAL 4, copying the value
-        ///   into a provided destination buffer.
-        /// </summary>
-        /// <param name="destination">The buffer in which to write.</param>
-        /// <param name="bytesWritten">
-        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
-        /// </param>
-        /// <returns>
-        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
-        ///   length to receive the value, otherwise
-        ///   <c>false</c> and the reader does not advance.
-        /// </returns>
-        /// <exception cref="CryptographicException">
-        ///   the next value does not have the correct tag --OR--
-        ///   the length encoding is not valid under the current encoding rules --OR--
-        ///   the contents are not valid under the current encoding rules
-        /// </exception>
-        /// <seealso cref="TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory{byte})"/>
-        /// <seealso cref="ReadOctetString()"/>
-        public bool TryCopyOctetStringBytes(
-            ArraySegment<byte> destination,
-            out int bytesWritten)
-        {
-            return TryCopyOctetStringBytes(
-                Asn1Tag.PrimitiveOctetString,
-                destination.AsSpan(),
-                out bytesWritten);
-        }
-
-        /// <summary>
-        ///   Reads the next value as an OCTET STRING with a specified tag, copying the value
-        ///   into a provided destination buffer.
-        /// </summary>
-        /// <param name="expectedTag">The tag to check for before reading.</param>
-        /// <param name="destination">The buffer in which to write.</param>
-        /// <param name="bytesWritten">
-        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
-        /// </param>
-        /// <returns>
-        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
-        ///   length to receive the value, otherwise
-        ///   <c>false</c> and the reader does not advance.
-        /// </returns>
-        /// <exception cref="CryptographicException">
-        ///   the next value does not have the correct tag --OR--
-        ///   the length encoding is not valid under the current encoding rules --OR--
-        ///   the contents are not valid under the current encoding rules
-        /// </exception>
-        /// <exception cref="ArgumentException">
-        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
-        ///   <see cref="TagClass.Universal"/>, but
-        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
-        ///   the method
-        /// </exception>
-        /// <seealso cref="TryReadPrimitiveOctetStringBytes(Asn1Tag,out ReadOnlyMemory{byte})"/>
-        /// <seealso cref="ReadOctetString(Asn1Tag)"/>
-        public bool TryCopyOctetStringBytes(
-            Asn1Tag expectedTag,
-            ArraySegment<byte> destination,
-            out int bytesWritten)
-        {
-            return TryCopyOctetStringBytes(
-                expectedTag,
-                destination.AsSpan(),
-                out bytesWritten);
-        }
-
-        /// <summary>
         ///   Reads the next value as an OCTET STRING with tag UNIVERSAL 4, returning the value
         ///   in a byte array.
         /// </summary>
@@ -189,7 +121,7 @@ namespace System.Security.Cryptography.Asn1
         ///   the length encoding is not valid under the current encoding rules --OR--
         ///   the contents are not valid under the current encoding rules
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveOctetStringBytes(out ReadOnlySpan{byte})"/>
         /// <seealso cref="TryCopyOctetStringBytes(Span{byte},out int)"/>
         /// <seealso cref="ReadOctetString(Asn1Tag)"/>
         public byte[] ReadOctetString()
@@ -216,22 +148,22 @@ namespace System.Security.Cryptography.Asn1
         ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
         ///   the method
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveOctetStringBytes(Asn1Tag,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveOctetStringBytes(Asn1Tag,out ReadOnlySpan{byte})"/>
         /// <seealso cref="TryCopyOctetStringBytes(Asn1Tag,Span{byte},out int)"/>
         /// <seealso cref="ReadOctetString()"/>
         public byte[] ReadOctetString(Asn1Tag expectedTag)
         {
-            ReadOnlyMemory<byte> memory;
+            ReadOnlySpan<byte> span;
 
-            if (TryReadPrimitiveOctetStringBytes(expectedTag, out memory))
+            if (TryReadPrimitiveOctetStringBytes(expectedTag, out span))
             {
-                return memory.ToArray();
+                return span.ToArray();
             }
 
-            memory = PeekEncodedValue();
+            span = PeekEncodedValue();
 
             // Guaranteed long enough
-            byte[] rented = CryptoPool.Rent(memory.Length);
+            byte[] rented = CryptoPool.Rent(span.Length);
             int dataLength = 0;
 
             try
@@ -257,7 +189,7 @@ namespace System.Security.Cryptography.Asn1
             out Asn1Tag actualTag,
             out int? contentLength,
             out int headerLength,
-            out ReadOnlyMemory<byte> contents,
+            out ReadOnlySpan<byte> contents,
             UniversalTagNumber universalTagNumber = UniversalTagNumber.OctetString)
         {
             actualTag = ReadTagAndLength(out contentLength, out headerLength);
@@ -270,12 +202,12 @@ namespace System.Security.Cryptography.Asn1
                     throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                 }
 
-                contents = default(ReadOnlyMemory<byte>);
+                contents = default;
                 return false;
             }
 
             Debug.Assert(contentLength.HasValue);
-            ReadOnlyMemory<byte> encodedValue = Slice(_data, headerLength, contentLength.Value);
+            ReadOnlySpan<byte> encodedValue = Slice(_data, headerLength, contentLength.Value);
 
             if (RuleSet == AsnEncodingRules.CER && encodedValue.Length > MaxCERSegmentSize)
             {
@@ -286,10 +218,10 @@ namespace System.Security.Cryptography.Asn1
             return true;
         }
 
-        private bool TryReadPrimitiveOctetStringBytes(
+        internal bool TryReadPrimitiveOctetStringBytes(
             Asn1Tag expectedTag,
             UniversalTagNumber universalTagNumber,
-            out ReadOnlyMemory<byte> contents)
+            out ReadOnlySpan<byte> contents)
         {
             if (TryReadPrimitiveOctetStringBytes(
                 expectedTag,
@@ -308,10 +240,10 @@ namespace System.Security.Cryptography.Asn1
 
         /// <summary>
         ///   Reads the next value as an OCTET STRING with tag UNIVERSAL 4, returning the contents
-        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        ///   as a <see cref="ReadOnlySpan{T}"/> over the original data.
         /// </summary>
         /// <param name="contents">
-        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
+        ///   On success, receives a <see cref="ReadOnlySpan{T}"/> over the original data
         ///   corresponding to the contents of the OCTET STRING.
         /// </param>
         /// <returns>
@@ -324,16 +256,16 @@ namespace System.Security.Cryptography.Asn1
         ///   the contents are not valid under the current encoding rules
         /// </exception>
         /// <seealso cref="TryCopyOctetStringBytes(Span{byte},out int)"/>
-        public bool TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> contents) =>
+        public bool TryReadPrimitiveOctetStringBytes(out ReadOnlySpan<byte> contents) =>
             TryReadPrimitiveOctetStringBytes(Asn1Tag.PrimitiveOctetString, out contents);
 
         /// <summary>
         ///   Reads the next value as an OCTET STRING with a specified tag, returning the contents
-        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        ///   as a <see cref="ReadOnlySpan{T}"/> over the original data.
         /// </summary>
         /// <param name="expectedTag">The tag to check for before reading.</param>
         /// <param name="contents">
-        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
+        ///   On success, receives a <see cref="ReadOnlySpan{T}"/> over the original data
         ///   corresponding to the value of the OCTET STRING.
         /// </param>
         /// <returns>
@@ -352,12 +284,12 @@ namespace System.Security.Cryptography.Asn1
         ///   the method
         /// </exception>
         /// <seealso cref="TryCopyOctetStringBytes(Asn1Tag,Span{byte},out int)"/>
-        public bool TryReadPrimitiveOctetStringBytes(Asn1Tag expectedTag, out ReadOnlyMemory<byte> contents)
+        public bool TryReadPrimitiveOctetStringBytes(Asn1Tag expectedTag, out ReadOnlySpan<byte> contents)
         {
             return TryReadPrimitiveOctetStringBytes(expectedTag, UniversalTagNumber.OctetString, out contents);
         }
 
-        private int CountConstructedOctetString(ReadOnlyMemory<byte> source, bool isIndefinite)
+        private int CountConstructedOctetString(ReadOnlySpan<byte> source, bool isIndefinite)
         {
             int contentLength = CopyConstructedOctetString(
                 source,
@@ -376,7 +308,7 @@ namespace System.Security.Cryptography.Asn1
         }
 
         private void CopyConstructedOctetString(
-            ReadOnlyMemory<byte> source,
+            ReadOnlySpan<byte> source,
             Span<byte> destination,
             bool isIndefinite,
             out int bytesRead,
@@ -391,7 +323,7 @@ namespace System.Security.Cryptography.Asn1
         }
 
         private int CopyConstructedOctetString(
-            ReadOnlyMemory<byte> source,
+            ReadOnlySpan<byte> source,
             Span<byte> destination,
             bool write,
             bool isIndefinite,
@@ -400,13 +332,14 @@ namespace System.Security.Cryptography.Asn1
             bytesRead = 0;
             int lastSegmentLength = MaxCERSegmentSize;
 
-            AsnReader? tmpReader = new AsnReader(source, RuleSet);
-            Stack<(AsnReader, bool, int)>? readerStack = null;
+            ReadOnlySpan<byte> originalSpan = _data;
+            AsnValueReader tmpReader = OpenUnchecked(source, RuleSet);
+            Stack<(int Offset, int Length, bool IsIndefinite, int BytesRead)>? readerStack = null;
             int totalLength = 0;
             Asn1Tag tag = Asn1Tag.ConstructedBitString;
             Span<byte> curDest = destination;
 
-            do
+            while (true)
             {
                 while (tmpReader.HasData)
                 {
@@ -424,7 +357,7 @@ namespace System.Security.Cryptography.Asn1
 
                         // The call to Slice here sanity checks the data bounds, length.Value is not
                         // reliable unless this call has succeeded.
-                        ReadOnlyMemory<byte> contents = Slice(tmpReader._data, headerLength, length.Value);
+                        ReadOnlySpan<byte> contents = Slice(tmpReader._data, headerLength, length.Value);
 
                         int localLen = headerLength + contents.Length;
                         tmpReader._data = tmpReader._data.Slice(localLen);
@@ -441,7 +374,7 @@ namespace System.Security.Cryptography.Asn1
 
                         if (write)
                         {
-                            contents.Span.CopyTo(curDest);
+                            contents.CopyTo(curDest);
                             curDest = curDest.Slice(contents.Length);
                         }
                     }
@@ -453,12 +386,12 @@ namespace System.Security.Cryptography.Asn1
 
                         if (readerStack?.Count > 0)
                         {
-                            (AsnReader topReader, bool wasIndefinite, int pushedBytesRead) = readerStack.Pop();
-                            topReader._data = topReader._data.Slice(bytesRead);
+                            (int topOffset, int topLength, bool wasIndefinite, int pushedBytesRead) = readerStack.Pop();
+                            ReadOnlySpan<byte> topSpan = originalSpan.Slice(topOffset, topLength);
+                            tmpReader._data = topSpan.Slice(bytesRead);
 
                             bytesRead += pushedBytesRead;
                             isIndefinite = wasIndefinite;
-                            tmpReader = topReader;
                         }
                         else
                         {
@@ -476,15 +409,18 @@ namespace System.Security.Cryptography.Asn1
 
                         if (readerStack == null)
                         {
-                            readerStack = new Stack<(AsnReader, bool, int)>();
+                            readerStack = new Stack<(int, int, bool, int)>();
                         }
 
-                        readerStack.Push((tmpReader, isIndefinite, bytesRead));
+                        if (!originalSpan.Overlaps(tmpReader._data, out int curOffset))
+                        {
+                            Debug.Fail("Non-overlapping data encountered...");
+                            throw new CryptographicException();
+                        }
 
-                        tmpReader = new AsnReader(
-                            Slice(tmpReader._data, headerLength, length),
-                            RuleSet);
+                        readerStack.Push((curOffset, tmpReader._data.Length, isIndefinite, bytesRead));
 
+                        tmpReader._data = Slice(tmpReader._data, headerLength, length);
                         bytesRead = headerLength;
                         isIndefinite = (length == null);
                     }
@@ -502,25 +438,23 @@ namespace System.Security.Cryptography.Asn1
 
                 if (readerStack?.Count > 0)
                 {
-                    (AsnReader topReader, bool wasIndefinite, int pushedBytesRead) = readerStack.Pop();
+                    (int topOffset, int topLength, bool wasIndefinite, int pushedBytesRead) = readerStack.Pop();
+                    ReadOnlySpan<byte> topSpan = originalSpan.Slice(topOffset, topLength);
 
-                    tmpReader = topReader;
-                    tmpReader._data = tmpReader._data.Slice(bytesRead);
+                    tmpReader._data = topSpan.Slice(bytesRead);
 
                     isIndefinite = wasIndefinite;
                     bytesRead += pushedBytesRead;
                 }
                 else
                 {
-                    tmpReader = null;
+                    return totalLength;
                 }
-            } while (tmpReader != null);
-
-            return totalLength;
+            }
         }
 
         private bool TryCopyConstructedOctetStringContents(
-            ReadOnlyMemory<byte> source,
+            ReadOnlySpan<byte> source,
             Span<byte> dest,
             bool isIndefinite,
             out int bytesRead,
@@ -556,16 +490,16 @@ namespace System.Security.Cryptography.Asn1
                 out Asn1Tag actualTag,
                 out int? contentLength,
                 out int headerLength,
-                out ReadOnlyMemory<byte> contentsOctets,
+                out ReadOnlySpan<byte> contentsOctets,
                 universalTagNumber))
             {
                 bytesRead = headerLength + contentsOctets.Length;
-                return contentsOctets.Span;
+                return contentsOctets;
             }
 
             Debug.Assert(actualTag.IsConstructed);
 
-            ReadOnlyMemory<byte> source = Slice(_data, headerLength, contentLength);
+            ReadOnlySpan<byte> source = Slice(_data, headerLength, contentLength);
             bool isIndefinite = contentLength == null;
             int octetStringLength = CountConstructedOctetString(source, isIndefinite);
 
@@ -588,4 +522,268 @@ namespace System.Security.Cryptography.Asn1
             return tmpSpace.Slice(0, bytesWritten);
         }
     }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as an OCTET STRING with tag UNIVERSAL 4, copying the value
+        ///   into a provided destination buffer.
+        /// </summary>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="bytesWritten">
+        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadOctetString()"/>
+        public bool TryCopyOctetStringBytes(
+            Span<byte> destination,
+            out int bytesWritten)
+        {
+            return TryCopyOctetStringBytes(
+                Asn1Tag.PrimitiveOctetString,
+                destination,
+                out bytesWritten);
+        }
+
+        /// <summary>
+        ///   Reads the next value as an OCTET STRING with a specified tag, copying the value
+        ///   into a provided destination buffer.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="bytesWritten">
+        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveOctetStringBytes(Asn1Tag,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadOctetString(Asn1Tag)"/>
+        public bool TryCopyOctetStringBytes(
+            Asn1Tag expectedTag,
+            Span<byte> destination,
+            out int bytesWritten)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+
+            if (valueReader.TryCopyOctetStringBytes(expectedTag, destination, out bytesWritten))
+            {
+                valueReader.MatchSlice(ref _data);
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        ///   Reads the next value as an OCTET STRING with tag UNIVERSAL 4, copying the value
+        ///   into a provided destination buffer.
+        /// </summary>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="bytesWritten">
+        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadOctetString()"/>
+        public bool TryCopyOctetStringBytes(
+            ArraySegment<byte> destination,
+            out int bytesWritten)
+        {
+            return TryCopyOctetStringBytes(
+                Asn1Tag.PrimitiveOctetString,
+                destination.AsSpan(),
+                out bytesWritten);
+        }
+
+        /// <summary>
+        ///   Reads the next value as an OCTET STRING with a specified tag, copying the value
+        ///   into a provided destination buffer.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="bytesWritten">
+        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveOctetStringBytes(Asn1Tag,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadOctetString(Asn1Tag)"/>
+        public bool TryCopyOctetStringBytes(
+            Asn1Tag expectedTag,
+            ArraySegment<byte> destination,
+            out int bytesWritten)
+        {
+            return TryCopyOctetStringBytes(
+                expectedTag,
+                destination.AsSpan(),
+                out bytesWritten);
+        }
+
+        /// <summary>
+        ///   Reads the next value as an OCTET STRING with tag UNIVERSAL 4, returning the value
+        ///   in a byte array.
+        /// </summary>
+        /// <returns>
+        ///   a copy of the contents in a newly allocated, precisely sized, array.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryCopyOctetStringBytes(Span{byte},out int)"/>
+        /// <seealso cref="ReadOctetString(Asn1Tag)"/>
+        public byte[] ReadOctetString()
+        {
+            return ReadOctetString(Asn1Tag.PrimitiveOctetString);
+        }
+
+        /// <summary>
+        ///   Reads the next value as an OCTET STRING with tag UNIVERSAL 4, returning the value
+        ///   in a byte array.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <returns>
+        ///   a copy of the value in a newly allocated, precisely sized, array.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveOctetStringBytes(Asn1Tag,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryCopyOctetStringBytes(Asn1Tag,Span{byte},out int)"/>
+        /// <seealso cref="ReadOctetString()"/>
+        public byte[] ReadOctetString(Asn1Tag expectedTag)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            byte[] ret = valueReader.ReadOctetString(expectedTag);
+            valueReader.MatchSlice(ref _data);
+            return ret;
+        }
+
+        /// <summary>
+        ///   Reads the next value as an OCTET STRING with tag UNIVERSAL 4, returning the contents
+        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        /// </summary>
+        /// <param name="contents">
+        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
+        ///   corresponding to the contents of the OCTET STRING.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if the OCTET STRING value had a primitive encoding,
+        ///   <c>false</c> and does not advance the reader if it had a constructed encoding.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="TryCopyOctetStringBytes(Span{byte},out int)"/>
+        public bool TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> contents) =>
+            TryReadPrimitiveOctetStringBytes(Asn1Tag.PrimitiveOctetString, out contents);
+
+        /// <summary>
+        ///   Reads the next value as an OCTET STRING with a specified tag, returning the contents
+        ///   as a <see cref="ReadOnlyMemory{T}"/> over the original data.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="contents">
+        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
+        ///   corresponding to the value of the OCTET STRING.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if the OCTET STRING value had a primitive encoding,
+        ///   <c>false</c> and does not advance the reader if it had a constructed encoding.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        /// <seealso cref="TryCopyOctetStringBytes(Asn1Tag,Span{byte},out int)"/>
+        public bool TryReadPrimitiveOctetStringBytes(Asn1Tag expectedTag, out ReadOnlyMemory<byte> contents)
+        {
+            return TryReadPrimitiveOctetStringBytes(expectedTag, UniversalTagNumber.OctetString, out contents);
+        }
+
+        private bool TryReadPrimitiveOctetStringBytes(
+            Asn1Tag expectedTag,
+            UniversalTagNumber universalTagNumber,
+            out ReadOnlyMemory<byte> contents)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            ReadOnlySpan<byte> span;
+
+            if (valueReader.TryReadPrimitiveOctetStringBytes(expectedTag, universalTagNumber, out span))
+            {
+                contents = AsnValueReader.Slice(_data, span);
+                valueReader.MatchSlice(ref _data);
+                return true;
+            }
+
+            contents = default;
+            return false;
+        }
+    }
 }
index be053e0..7569239 100644 (file)
@@ -11,7 +11,7 @@ using System.Text;
 #nullable enable
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         /// <summary>
         ///   Reads the next value as an OBJECT IDENTIFIER with tag UNIVERSAL 6, returning
@@ -218,8 +218,7 @@ namespace System.Security.Cryptography.Asn1
                 throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
             }
 
-            ReadOnlyMemory<byte> contentsMemory = Slice(_data, headerLength, length!.Value);
-            ReadOnlySpan<byte> contents = contentsMemory.Span;
+            ReadOnlySpan<byte> contents = Slice(_data, headerLength, length!.Value);
 
             // Each byte can contribute a 3 digit value and a '.' (e.g. "126."), but usually
             // they convey one digit and a separator.
@@ -311,4 +310,79 @@ namespace System.Security.Cryptography.Asn1
             return builder.ToString();
         }
     }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as an OBJECT IDENTIFIER with tag UNIVERSAL 6, returning
+        ///   the value in a dotted decimal format string.
+        /// </summary>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public string ReadObjectIdentifierAsString() =>
+            ReadObjectIdentifierAsString(Asn1Tag.ObjectIdentifier);
+
+        /// <summary>
+        ///   Reads the next value as an OBJECT IDENTIFIER with a specified tag, returning
+        ///   the value in a dotted decimal format string.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public string ReadObjectIdentifierAsString(Asn1Tag expectedTag)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            string oidValue = valueReader.ReadObjectIdentifierAsString(expectedTag);
+            valueReader.MatchSlice(ref _data);
+            return oidValue;
+        }
+
+        /// <summary>
+        ///   Reads the next value as an OBJECT IDENTIFIER with tag UNIVERSAL 6, returning
+        ///   the value as an <see cref="Oid"/>.
+        /// </summary>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public Oid ReadObjectIdentifier() =>
+            ReadObjectIdentifier(Asn1Tag.ObjectIdentifier);
+
+        /// <summary>
+        ///   Reads the next value as an OBJECT IDENTIFIER with a specified tag, returning
+        ///   the value as an <see cref="Oid"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public Oid ReadObjectIdentifier(Asn1Tag expectedTag)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            Oid oid = valueReader.ReadObjectIdentifier(expectedTag);
+            valueReader.MatchSlice(ref _data);
+            return oid;
+        }
+    }
 }
index 3ee00f7..6f89866 100644 (file)
@@ -4,15 +4,15 @@
 
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         /// <summary>
         ///   Reads the next value as a SEQUENCE or SEQUENCE-OF with tag UNIVERSAL 16
-        ///   and returns the result as an <see cref="AsnReader"/> positioned at the first
+        ///   and returns the result as an <see cref="AsnValueReader"/> positioned at the first
         ///   value in the sequence (or with <see cref="HasData"/> == <c>false</c>).
         /// </summary>
         /// <returns>
-        ///   an <see cref="AsnReader"/> positioned at the first
+        ///   an <see cref="AsnValueReader"/> positioned at the first
         ///   value in the sequence (or with <see cref="HasData"/> == <c>false</c>).
         /// </returns>
         /// <remarks>
@@ -25,16 +25,16 @@ namespace System.Security.Cryptography.Asn1
         ///   the contents are not valid under the current encoding rules
         /// </exception>
         /// <see cref="ReadSequence(Asn1Tag)"/>
-        public AsnReader ReadSequence() => ReadSequence(Asn1Tag.Sequence);
+        public AsnValueReader ReadSequence() => ReadSequence(Asn1Tag.Sequence);
 
         /// <summary>
         ///   Reads the next value as a SEQUENCE or SEQUENCE-OF with the specified tag
-        ///   and returns the result as an <see cref="AsnReader"/> positioned at the first
+        ///   and returns the result as an <see cref="AsnValueReader"/> positioned at the first
         ///   value in the sequence (or with <see cref="HasData"/> == <c>false</c>).
         /// </summary>
         /// <param name="expectedTag">The tag to check for before reading.</param>
         /// <returns>
-        ///   an <see cref="AsnReader"/> positioned at the first
+        ///   an <see cref="AsnValueReader"/> positioned at the first
         ///   value in the sequence (or with <see cref="HasData"/> == <c>false</c>).
         /// </returns>
         /// <remarks>
@@ -52,7 +52,7 @@ namespace System.Security.Cryptography.Asn1
         ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
         ///   the method
         /// </exception>
-        public AsnReader ReadSequence(Asn1Tag expectedTag)
+        public AsnValueReader ReadSequence(Asn1Tag expectedTag)
         {
             Asn1Tag tag = ReadTagAndLength(out int? length, out int headerLength);
             CheckExpectedTag(tag, expectedTag, UniversalTagNumber.Sequence);
@@ -72,10 +72,71 @@ namespace System.Security.Cryptography.Asn1
                 suffix = EndOfContentsEncodedLength;
             }
 
-            ReadOnlyMemory<byte> contents = Slice(_data, headerLength, length.Value);
+            ReadOnlySpan<byte> contents = Slice(_data, headerLength, length.Value);
 
             _data = _data.Slice(headerLength + contents.Length + suffix);
-            return new AsnReader(contents, RuleSet);
+            return OpenUnchecked(contents, RuleSet);
+        }
+    }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as a SEQUENCE or SEQUENCE-OF with tag UNIVERSAL 16
+        ///   and returns the result as an <see cref="AsnReader"/> positioned at the first
+        ///   value in the sequence (or with <see cref="HasData"/> == <c>false</c>).
+        /// </summary>
+        /// <returns>
+        ///   an <see cref="AsnReader"/> positioned at the first
+        ///   value in the sequence (or with <see cref="HasData"/> == <c>false</c>).
+        /// </returns>
+        /// <remarks>
+        ///   the nested content is not evaluated by this method, and may contain data
+        ///   which is not valid under the current encoding rules.
+        /// </remarks>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <see cref="ReadSequence(Asn1Tag)"/>
+        public AsnReader ReadSequence() => ReadSequence(Asn1Tag.Sequence);
+
+        /// <summary>
+        ///   Reads the next value as a SEQUENCE or SEQUENCE-OF with the specified tag
+        ///   and returns the result as an <see cref="AsnReader"/> positioned at the first
+        ///   value in the sequence (or with <see cref="HasData"/> == <c>false</c>).
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <returns>
+        ///   an <see cref="AsnReader"/> positioned at the first
+        ///   value in the sequence (or with <see cref="HasData"/> == <c>false</c>).
+        /// </returns>
+        /// <remarks>
+        ///   the nested content is not evaluated by this method, and may contain data
+        ///   which is not valid under the current encoding rules.
+        /// </remarks>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public AsnReader ReadSequence(Asn1Tag expectedTag)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            AsnValueReader innerValueReader = valueReader.ReadSequence(expectedTag);
+
+            AsnReader ret = new AsnReader(_data, RuleSet);
+            innerValueReader.MatchSlice(ref ret._data);
+
+            valueReader.MatchSlice(ref _data);
+            return ret;
         }
     }
 }
index a72b4f6..cd3adaa 100644 (file)
@@ -4,11 +4,11 @@
 
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         /// <summary>
         ///   Reads the next value as a SET-OF with the specified tag
-        ///   and returns the result as an <see cref="AsnReader"/> positioned at the first
+        ///   and returns the result as an <see cref="AsnValueReader"/> positioned at the first
         ///   value in the set-of (or with <see cref="HasData"/> == <c>false</c>).
         /// </summary>
         /// <param name="skipSortOrderValidation">
@@ -17,7 +17,7 @@ namespace System.Security.Cryptography.Asn1
         ///   encoding rules say sorting was required (CER and DER).
         /// </param>
         /// <returns>
-        ///   an <see cref="AsnReader"/> positioned at the first
+        ///   an <see cref="AsnValueReader"/> positioned at the first
         ///   value in the set-of (or with <see cref="HasData"/> == <c>false</c>).
         /// </returns>
         /// <remarks>
@@ -29,12 +29,12 @@ namespace System.Security.Cryptography.Asn1
         ///   the length encoding is not valid under the current encoding rules --OR--
         ///   the contents are not valid under the current encoding rules
         /// </exception>
-        public AsnReader ReadSetOf(bool skipSortOrderValidation = false) =>
+        public AsnValueReader ReadSetOf(bool skipSortOrderValidation = false) =>
             ReadSetOf(Asn1Tag.SetOf, skipSortOrderValidation);
 
         /// <summary>
         ///   Reads the next value as a SET-OF with the specified tag
-        ///   and returns the result as an <see cref="AsnReader"/> positioned at the first
+        ///   and returns the result as an <see cref="AsnValueReader"/> positioned at the first
         ///   value in the set-of (or with <see cref="HasData"/> == <c>false</c>).
         /// </summary>
         /// <param name="expectedTag">The tag to check for before reading.</param>
@@ -44,7 +44,7 @@ namespace System.Security.Cryptography.Asn1
         ///   encoding rules say sorting was required (CER and DER).
         /// </param>
         /// <returns>
-        ///   an <see cref="AsnReader"/> positioned at the first
+        ///   an <see cref="AsnValueReader"/> positioned at the first
         ///   value in the set-of (or with <see cref="HasData"/> == <c>false</c>).
         /// </returns>
         /// <remarks>
@@ -62,7 +62,7 @@ namespace System.Security.Cryptography.Asn1
         ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
         ///   the method
         /// </exception>
-        public AsnReader ReadSetOf(Asn1Tag expectedTag, bool skipSortOrderValidation = false)
+        public AsnValueReader ReadSetOf(Asn1Tag expectedTag, bool skipSortOrderValidation = false)
         {
             Asn1Tag tag = ReadTagAndLength(out int? length, out int headerLength);
             CheckExpectedTag(tag, expectedTag, UniversalTagNumber.SetOf);
@@ -81,7 +81,7 @@ namespace System.Security.Cryptography.Asn1
                 suffix = EndOfContentsEncodedLength;
             }
 
-            ReadOnlyMemory<byte> contents = Slice(_data, headerLength, length.Value);
+            ReadOnlySpan<byte> contents = Slice(_data, headerLength, length.Value);
 
             if (!skipSortOrderValidation)
             {
@@ -90,16 +90,15 @@ namespace System.Security.Cryptography.Asn1
                 if (RuleSet == AsnEncodingRules.DER ||
                     RuleSet == AsnEncodingRules.CER)
                 {
-                    AsnReader reader = new AsnReader(contents, RuleSet);
-                    ReadOnlyMemory<byte> current = ReadOnlyMemory<byte>.Empty;
-                    SetOfValueComparer comparer = SetOfValueComparer.Instance;
+                    AsnValueReader reader = OpenUnchecked(contents, RuleSet);
+                    ReadOnlySpan<byte> current = ReadOnlySpan<byte>.Empty;
 
                     while (reader.HasData)
                     {
-                        ReadOnlyMemory<byte> previous = current;
+                        ReadOnlySpan<byte> previous = current;
                         current = reader.ReadEncodedValue();
 
-                        if (comparer.Compare(current, previous) < 0)
+                        if (SetOfValueComparer.Compare(current, previous) < 0)
                         {
                             throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
                         }
@@ -108,7 +107,78 @@ namespace System.Security.Cryptography.Asn1
             }
 
             _data = _data.Slice(headerLength + contents.Length + suffix);
-            return new AsnReader(contents, RuleSet);
+            return OpenUnchecked(contents, RuleSet);
+        }
+    }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as a SET-OF with the specified tag
+        ///   and returns the result as an <see cref="AsnReader"/> positioned at the first
+        ///   value in the set-of (or with <see cref="HasData"/> == <c>false</c>).
+        /// </summary>
+        /// <param name="skipSortOrderValidation">
+        ///   <c>true</c> to always accept the data in the order it is presented,
+        ///   <c>false</c> to verify that the data is sorted correctly when the
+        ///   encoding rules say sorting was required (CER and DER).
+        /// </param>
+        /// <returns>
+        ///   an <see cref="AsnReader"/> positioned at the first
+        ///   value in the set-of (or with <see cref="HasData"/> == <c>false</c>).
+        /// </returns>
+        /// <remarks>
+        ///   the nested content is not evaluated by this method (aside from sort order, when
+        ///   required), and may contain data which is not valid under the current encoding rules.
+        /// </remarks>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        public AsnReader ReadSetOf(bool skipSortOrderValidation = false) =>
+            ReadSetOf(Asn1Tag.SetOf, skipSortOrderValidation);
+
+        /// <summary>
+        ///   Reads the next value as a SET-OF with the specified tag
+        ///   and returns the result as an <see cref="AsnReader"/> positioned at the first
+        ///   value in the set-of (or with <see cref="HasData"/> == <c>false</c>).
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="skipSortOrderValidation">
+        ///   <c>true</c> to always accept the data in the order it is presented,
+        ///   <c>false</c> to verify that the data is sorted correctly when the
+        ///   encoding rules say sorting was required (CER and DER).
+        /// </param>
+        /// <returns>
+        ///   an <see cref="AsnReader"/> positioned at the first
+        ///   value in the set-of (or with <see cref="HasData"/> == <c>false</c>).
+        /// </returns>
+        /// <remarks>
+        ///   the nested content is not evaluated by this method (aside from sort order, when
+        ///   required), and may contain data which is not valid under the current encoding rules.
+        /// </remarks>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        public AsnReader ReadSetOf(Asn1Tag expectedTag, bool skipSortOrderValidation = false)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            AsnValueReader innerValueReader = valueReader.ReadSetOf(expectedTag, skipSortOrderValidation);
+
+            AsnReader ret = new AsnReader(_data, RuleSet);
+            innerValueReader.MatchSlice(ref ret._data);
+
+            valueReader.MatchSlice(ref _data);
+            return ret;
         }
     }
 }
index 02afa6d..6775e77 100644 (file)
@@ -10,18 +10,18 @@ using System.Text;
 #nullable enable
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         /// <summary>
         ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
-        ///   encoding type, returning the contents as an unprocessed <see cref="ReadOnlyMemory{T}"/>
+        ///   encoding type, returning the contents as an unprocessed <see cref="ReadOnlySpan{T}"/>
         ///   over the original data.
         /// </summary>
         /// <param name="encodingType">
         ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
         /// </param>
         /// <param name="contents">
-        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
+        ///   On success, receives a <see cref="ReadOnlySpan{T}"/> over the original data
         ///   corresponding to the contents of the character string.
         /// </param>
         /// <returns>
@@ -42,7 +42,7 @@ namespace System.Security.Cryptography.Asn1
         /// <seealso cref="TryCopyCharacterStringBytes(UniversalTagNumber,Span{byte},out int)"/>
         public bool TryReadPrimitiveCharacterStringBytes(
             UniversalTagNumber encodingType,
-            out ReadOnlyMemory<byte> contents)
+            out ReadOnlySpan<byte> contents)
         {
             return TryReadPrimitiveCharacterStringBytes(
                 new Asn1Tag(encodingType),
@@ -52,14 +52,14 @@ namespace System.Security.Cryptography.Asn1
 
         /// <summary>
         ///   Reads the next value as a character with a specified tag, returning the contents
-        ///   as an unprocessed <see cref="ReadOnlyMemory{T}"/> over the original data.
+        ///   as an unprocessed <see cref="ReadOnlySpan{T}"/> over the original data.
         /// </summary>
         /// <param name="expectedTag">The tag to check for before reading.</param>
         /// <param name="encodingType">
         ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
         /// </param>
         /// <param name="contents">
-        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
+        ///   On success, receives a <see cref="ReadOnlySpan{T}"/> over the original data
         ///   corresponding to the value of the OCTET STRING.
         /// </param>
         /// <returns>
@@ -84,7 +84,7 @@ namespace System.Security.Cryptography.Asn1
         public bool TryReadPrimitiveCharacterStringBytes(
             Asn1Tag expectedTag,
             UniversalTagNumber encodingType,
-            out ReadOnlyMemory<byte> contents)
+            out ReadOnlySpan<byte> contents)
         {
             CheckCharacterStringEncodingType(encodingType);
 
@@ -119,7 +119,7 @@ namespace System.Security.Cryptography.Asn1
         ///   the length encoding is not valid under the current encoding rules --OR--
         ///   the contents are not valid under the current encoding rules
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlySpan{byte})"/>
         /// <seealso cref="ReadCharacterString(UniversalTagNumber)"/>
         /// <seealso cref="TryCopyCharacterString(UniversalTagNumber,Span{char},out int)"/>
         public bool TryCopyCharacterStringBytes(
@@ -168,7 +168,7 @@ namespace System.Security.Cryptography.Asn1
         ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
         ///   <paramref name="encodingType"/>.
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlySpan{byte})"/>
         /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
         /// <seealso cref="TryCopyCharacterString(Asn1Tag,UniversalTagNumber,Span{char},out int)"/>
         public bool TryCopyCharacterStringBytes(
@@ -221,7 +221,7 @@ namespace System.Security.Cryptography.Asn1
         ///   the length encoding is not valid under the current encoding rules --OR--
         ///   the contents are not valid under the current encoding rules
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlySpan{byte})"/>
         /// <seealso cref="ReadCharacterString(UniversalTagNumber)"/>
         /// <seealso cref="TryCopyCharacterString(UniversalTagNumber,Span{char},out int)"/>
         public bool TryCopyCharacterStringBytes(
@@ -270,7 +270,7 @@ namespace System.Security.Cryptography.Asn1
         ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
         ///   <paramref name="encodingType"/>.
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlySpan{byte})"/>
         /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
         /// <seealso cref="TryCopyCharacterString(Asn1Tag,UniversalTagNumber,Span{char},out int)"/>
         public bool TryCopyCharacterStringBytes(
@@ -311,7 +311,7 @@ namespace System.Security.Cryptography.Asn1
         ///   the contents are not valid under the current encoding rules --OR--
         ///   the string did not successfully decode
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlySpan{byte})"/>
         /// <seealso cref="ReadCharacterString(UniversalTagNumber)"/>
         /// <seealso cref="TryCopyCharacterStringBytes(UniversalTagNumber,Span{byte},out int)"/>
         public bool TryCopyCharacterString(
@@ -358,7 +358,7 @@ namespace System.Security.Cryptography.Asn1
         ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
         ///   <paramref name="encodingType"/>.
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlySpan{byte})"/>
         /// <seealso cref="TryCopyCharacterStringBytes(Asn1Tag,UniversalTagNumber,Span{byte},out int)"/>
         /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
         public bool TryCopyCharacterString(
@@ -373,95 +373,6 @@ namespace System.Security.Cryptography.Asn1
 
         /// <summary>
         ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
-        ///   encoding type, copying the decoded value into a provided destination buffer.
-        /// </summary>
-        /// <param name="encodingType">
-        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
-        /// </param>
-        /// <param name="destination">The buffer in which to write.</param>
-        /// <param name="charsWritten">
-        ///   On success, receives the number of chars written to <paramref name="destination"/>.
-        /// </param>
-        /// <returns>
-        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
-        ///   length to receive the value, otherwise
-        ///   <c>false</c> and the reader does not advance.
-        /// </returns>
-        /// <exception cref="ArgumentOutOfRangeException">
-        ///   <paramref name="encodingType"/> is not a known character string type.
-        /// </exception>
-        /// <exception cref="CryptographicException">
-        ///   the next value does not have the correct tag --OR--
-        ///   the length encoding is not valid under the current encoding rules --OR--
-        ///   the contents are not valid under the current encoding rules --OR--
-        ///   the string did not successfully decode
-        /// </exception>
-        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
-        /// <seealso cref="ReadCharacterString(UniversalTagNumber)"/>
-        /// <seealso cref="TryCopyCharacterStringBytes(UniversalTagNumber,ArraySegment{byte},out int)"/>
-        /// <seealso cref="TryCopyCharacterString(Asn1Tag,UniversalTagNumber,ArraySegment{char},out int)"/>
-        public bool TryCopyCharacterString(
-            UniversalTagNumber encodingType,
-            ArraySegment<char> destination,
-            out int charsWritten)
-        {
-            return TryCopyCharacterString(
-                new Asn1Tag(encodingType),
-                encodingType,
-                destination.AsSpan(),
-                out charsWritten);
-        }
-
-        /// <summary>
-        ///   Reads the next value as character string with the specified tag and
-        ///   encoding type, copying the decoded value into a provided destination buffer.
-        /// </summary>
-        /// <param name="expectedTag">The tag to check for before reading.</param>
-        /// <param name="encodingType">
-        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
-        /// </param>
-        /// <param name="destination">The buffer in which to write.</param>
-        /// <param name="charsWritten">
-        ///   On success, receives the number of chars written to <paramref name="destination"/>.
-        /// </param>
-        /// <returns>
-        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
-        ///   length to receive the value, otherwise
-        ///   <c>false</c> and the reader does not advance.
-        /// </returns>
-        /// <exception cref="ArgumentOutOfRangeException">
-        ///   <paramref name="encodingType"/> is not a known character string type.
-        /// </exception>
-        /// <exception cref="CryptographicException">
-        ///   the next value does not have the correct tag --OR--
-        ///   the length encoding is not valid under the current encoding rules --OR--
-        ///   the contents are not valid under the current encoding rules --OR--
-        ///   the string did not successfully decode
-        /// </exception>
-        /// <exception cref="ArgumentException">
-        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
-        ///   <see cref="TagClass.Universal"/>, but
-        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
-        ///   <paramref name="encodingType"/>.
-        /// </exception>
-        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
-        /// <seealso cref="TryCopyCharacterStringBytes(Asn1Tag,UniversalTagNumber,ArraySegment{byte},out int)"/>
-        /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
-        public bool TryCopyCharacterString(
-            Asn1Tag expectedTag,
-            UniversalTagNumber encodingType,
-            ArraySegment<char> destination,
-            out int charsWritten)
-        {
-            return TryCopyCharacterString(
-                expectedTag,
-                encodingType,
-                destination.AsSpan(),
-                out charsWritten);
-        }
-
-        /// <summary>
-        ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
         ///   encoding type, returning the decoded value as a <see cref="string"/>.
         /// </summary>
         /// <param name="encodingType">
@@ -479,7 +390,7 @@ namespace System.Security.Cryptography.Asn1
         ///   the contents are not valid under the current encoding rules --OR--
         ///   the string did not successfully decode
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlySpan{byte})"/>
         /// <seealso cref="TryCopyCharacterStringBytes(UniversalTagNumber,Span{byte},out int)"/>
         /// <seealso cref="TryCopyCharacterString(UniversalTagNumber,Span{char},out int)"/>
         /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
@@ -512,7 +423,7 @@ namespace System.Security.Cryptography.Asn1
         ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
         ///   <paramref name="encodingType"/>.
         /// </exception>
-        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlySpan{byte})"/>
         /// <seealso cref="TryCopyCharacterStringBytes(Asn1Tag,UniversalTagNumber,Span{byte},out int)"/>
         /// <seealso cref="TryCopyCharacterString(Asn1Tag,UniversalTagNumber,Span{char},out int)"/>
         public string ReadCharacterString(Asn1Tag expectedTag, UniversalTagNumber encodingType)
@@ -535,7 +446,7 @@ namespace System.Security.Cryptography.Asn1
                 out Asn1Tag actualTag,
                 out int? contentLength,
                 out int headerLength,
-                out ReadOnlyMemory<byte> contents,
+                out ReadOnlySpan<byte> contents,
                 universalTagNumber))
             {
                 bytesWritten = contents.Length;
@@ -547,7 +458,7 @@ namespace System.Security.Cryptography.Asn1
                     return false;
                 }
 
-                contents.Span.CopyTo(destination);
+                contents.CopyTo(destination);
                 bytesRead = headerLength + bytesWritten;
                 return true;
             }
@@ -726,4 +637,527 @@ namespace System.Security.Cryptography.Asn1
             throw new ArgumentOutOfRangeException(nameof(encodingType));
         }
     }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
+        ///   encoding type, returning the contents as an unprocessed <see cref="ReadOnlyMemory{T}"/>
+        ///   over the original data.
+        /// </summary>
+        /// <param name="encodingType">
+        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
+        /// </param>
+        /// <param name="contents">
+        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
+        ///   corresponding to the contents of the character string.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if the value had a primitive encoding,
+        ///   <c>false</c> and does not advance the reader if it had a constructed encoding.
+        /// </returns>
+        /// <remarks>
+        ///   This method does not determine if the string used only characters defined by the encoding.
+        /// </remarks>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <paramref name="encodingType"/> is not a known character string type.
+        /// </exception>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="TryCopyCharacterStringBytes(UniversalTagNumber,Span{byte},out int)"/>
+        public bool TryReadPrimitiveCharacterStringBytes(
+            UniversalTagNumber encodingType,
+            out ReadOnlyMemory<byte> contents)
+        {
+            return TryReadPrimitiveCharacterStringBytes(
+                new Asn1Tag(encodingType),
+                encodingType,
+                out contents);
+        }
+
+        /// <summary>
+        ///   Reads the next value as a character with a specified tag, returning the contents
+        ///   as an unprocessed <see cref="ReadOnlyMemory{T}"/> over the original data.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="encodingType">
+        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
+        /// </param>
+        /// <param name="contents">
+        ///   On success, receives a <see cref="ReadOnlyMemory{T}"/> over the original data
+        ///   corresponding to the value of the OCTET STRING.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if the OCTET STRING value had a primitive encoding,
+        ///   <c>false</c> and does not advance the reader if it had a constructed encoding.
+        /// </returns>
+        /// <remarks>
+        ///   This method does not determine if the string used only characters defined by the encoding.
+        /// </remarks>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
+        ///   <paramref name="encodingType"/>.
+        /// </exception>
+        /// <seealso cref="TryCopyCharacterStringBytes(Asn1Tag,UniversalTagNumber,Span{byte},out int)"/>
+        public bool TryReadPrimitiveCharacterStringBytes(
+            Asn1Tag expectedTag,
+            UniversalTagNumber encodingType,
+            out ReadOnlyMemory<byte> contents)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            ReadOnlySpan<byte> span;
+
+            if (valueReader.TryReadPrimitiveCharacterStringBytes(expectedTag, encodingType, out span))
+            {
+                contents = AsnValueReader.Slice(_data, span);
+                valueReader.MatchSlice(ref _data);
+                return true;
+            }
+
+            contents = default;
+            return false;
+        }
+
+        /// <summary>
+        ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
+        ///   encoding type, copying the value into a provided destination buffer.
+        /// </summary>
+        /// <param name="encodingType">
+        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
+        /// </param>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="bytesWritten">
+        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <remarks>
+        ///   This method does not determine if the string used only characters defined by the encoding.
+        /// </remarks>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <paramref name="encodingType"/> is not a known character string type.
+        /// </exception>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadCharacterString(UniversalTagNumber)"/>
+        /// <seealso cref="TryCopyCharacterString(UniversalTagNumber,Span{char},out int)"/>
+        public bool TryCopyCharacterStringBytes(
+            UniversalTagNumber encodingType,
+            Span<byte> destination,
+            out int bytesWritten)
+        {
+            return TryCopyCharacterStringBytes(
+                new Asn1Tag(encodingType),
+                encodingType,
+                destination,
+                out bytesWritten);
+        }
+
+        /// <summary>
+        ///   Reads the next value as character string with the specified tag and
+        ///   encoding type, copying the value into a provided destination buffer.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="encodingType">
+        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
+        /// </param>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="bytesWritten">
+        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <remarks>
+        ///   This method does not determine if the string used only characters defined by the encoding.
+        /// </remarks>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <paramref name="encodingType"/> is not a known character string type.
+        /// </exception>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
+        ///   <paramref name="encodingType"/>.
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
+        /// <seealso cref="TryCopyCharacterString(Asn1Tag,UniversalTagNumber,Span{char},out int)"/>
+        public bool TryCopyCharacterStringBytes(
+            Asn1Tag expectedTag,
+            UniversalTagNumber encodingType,
+            Span<byte> destination,
+            out int bytesWritten)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+
+            if (valueReader.TryCopyCharacterStringBytes(expectedTag, encodingType, destination, out bytesWritten))
+            {
+                valueReader.MatchSlice(ref _data);
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
+        ///   encoding type, copying the value into a provided destination buffer.
+        /// </summary>
+        /// <param name="encodingType">
+        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
+        /// </param>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="bytesWritten">
+        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <remarks>
+        ///   This method does not determine if the string used only characters defined by the encoding.
+        /// </remarks>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <paramref name="encodingType"/> is not a known character string type.
+        /// </exception>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadCharacterString(UniversalTagNumber)"/>
+        /// <seealso cref="TryCopyCharacterString(UniversalTagNumber,Span{char},out int)"/>
+        public bool TryCopyCharacterStringBytes(
+            UniversalTagNumber encodingType,
+            ArraySegment<byte> destination,
+            out int bytesWritten)
+        {
+            return TryCopyCharacterStringBytes(
+                new Asn1Tag(encodingType),
+                encodingType,
+                destination.AsSpan(),
+                out bytesWritten);
+        }
+
+        /// <summary>
+        ///   Reads the next value as character string with the specified tag and
+        ///   encoding type, copying the value into a provided destination buffer.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="encodingType">
+        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
+        /// </param>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="bytesWritten">
+        ///   On success, receives the number of bytes written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <remarks>
+        ///   This method does not determine if the string used only characters defined by the encoding.
+        /// </remarks>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <paramref name="encodingType"/> is not a known character string type.
+        /// </exception>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
+        ///   <paramref name="encodingType"/>.
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
+        /// <seealso cref="TryCopyCharacterString(Asn1Tag,UniversalTagNumber,Span{char},out int)"/>
+        public bool TryCopyCharacterStringBytes(
+            Asn1Tag expectedTag,
+            UniversalTagNumber encodingType,
+            ArraySegment<byte> destination,
+            out int bytesWritten)
+        {
+            return TryCopyCharacterStringBytes(
+                expectedTag,
+                encodingType,
+                destination.AsSpan(),
+                out bytesWritten);
+        }
+
+        /// <summary>
+        ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
+        ///   encoding type, copying the decoded value into a provided destination buffer.
+        /// </summary>
+        /// <param name="encodingType">
+        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
+        /// </param>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="charsWritten">
+        ///   On success, receives the number of chars written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <paramref name="encodingType"/> is not a known character string type.
+        /// </exception>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the string did not successfully decode
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadCharacterString(UniversalTagNumber)"/>
+        /// <seealso cref="TryCopyCharacterStringBytes(UniversalTagNumber,Span{byte},out int)"/>
+        public bool TryCopyCharacterString(
+            UniversalTagNumber encodingType,
+            Span<char> destination,
+            out int charsWritten)
+        {
+            return TryCopyCharacterString(
+                new Asn1Tag(encodingType),
+                encodingType,
+                destination,
+                out charsWritten);
+        }
+
+        /// <summary>
+        ///   Reads the next value as character string with the specified tag and
+        ///   encoding type, copying the decoded value into a provided destination buffer.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="encodingType">
+        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
+        /// </param>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="charsWritten">
+        ///   On success, receives the number of chars written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <paramref name="encodingType"/> is not a known character string type.
+        /// </exception>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the string did not successfully decode
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
+        ///   <paramref name="encodingType"/>.
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryCopyCharacterStringBytes(Asn1Tag,UniversalTagNumber,Span{byte},out int)"/>
+        /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
+        public bool TryCopyCharacterString(
+            Asn1Tag expectedTag,
+            UniversalTagNumber encodingType,
+            Span<char> destination,
+            out int charsWritten)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+
+            if (valueReader.TryCopyCharacterString(expectedTag, encodingType, destination, out charsWritten))
+            {
+                valueReader.MatchSlice(ref _data);
+                return true;
+            }
+
+            return false;
+        }
+
+        /// <summary>
+        ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
+        ///   encoding type, copying the decoded value into a provided destination buffer.
+        /// </summary>
+        /// <param name="encodingType">
+        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
+        /// </param>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="charsWritten">
+        ///   On success, receives the number of chars written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <paramref name="encodingType"/> is not a known character string type.
+        /// </exception>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the string did not successfully decode
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="ReadCharacterString(UniversalTagNumber)"/>
+        /// <seealso cref="TryCopyCharacterStringBytes(UniversalTagNumber,ArraySegment{byte},out int)"/>
+        /// <seealso cref="TryCopyCharacterString(Asn1Tag,UniversalTagNumber,ArraySegment{char},out int)"/>
+        public bool TryCopyCharacterString(
+            UniversalTagNumber encodingType,
+            ArraySegment<char> destination,
+            out int charsWritten)
+        {
+            return TryCopyCharacterString(
+                new Asn1Tag(encodingType),
+                encodingType,
+                destination.AsSpan(),
+                out charsWritten);
+        }
+
+        /// <summary>
+        ///   Reads the next value as character string with the specified tag and
+        ///   encoding type, copying the decoded value into a provided destination buffer.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="encodingType">
+        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
+        /// </param>
+        /// <param name="destination">The buffer in which to write.</param>
+        /// <param name="charsWritten">
+        ///   On success, receives the number of chars written to <paramref name="destination"/>.
+        /// </param>
+        /// <returns>
+        ///   <c>true</c> and advances the reader if <paramref name="destination"/> had sufficient
+        ///   length to receive the value, otherwise
+        ///   <c>false</c> and the reader does not advance.
+        /// </returns>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <paramref name="encodingType"/> is not a known character string type.
+        /// </exception>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the string did not successfully decode
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
+        ///   <paramref name="encodingType"/>.
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryCopyCharacterStringBytes(Asn1Tag,UniversalTagNumber,ArraySegment{byte},out int)"/>
+        /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
+        public bool TryCopyCharacterString(
+            Asn1Tag expectedTag,
+            UniversalTagNumber encodingType,
+            ArraySegment<char> destination,
+            out int charsWritten)
+        {
+            return TryCopyCharacterString(
+                expectedTag,
+                encodingType,
+                destination.AsSpan(),
+                out charsWritten);
+        }
+
+        /// <summary>
+        ///   Reads the next value as character string with a UNIVERSAL tag appropriate to the specified
+        ///   encoding type, returning the decoded value as a <see cref="string"/>.
+        /// </summary>
+        /// <param name="encodingType">
+        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
+        /// </param>
+        /// <returns>
+        ///   the decoded value as a <see cref="string"/>.
+        /// </returns>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <paramref name="encodingType"/> is not a known character string type.
+        /// </exception>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the string did not successfully decode
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryCopyCharacterStringBytes(UniversalTagNumber,Span{byte},out int)"/>
+        /// <seealso cref="TryCopyCharacterString(UniversalTagNumber,Span{char},out int)"/>
+        /// <seealso cref="ReadCharacterString(Asn1Tag,UniversalTagNumber)"/>
+        public string ReadCharacterString(UniversalTagNumber encodingType) =>
+            ReadCharacterString(new Asn1Tag(encodingType), encodingType);
+
+        /// <summary>
+        ///   Reads the next value as character string with the specified tag and
+        ///   encoding type, returning the decoded value as a <see cref="string"/>.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="encodingType">
+        ///   A <see cref="UniversalTagNumber"/> corresponding to the value type to process.
+        /// </param>
+        /// <returns>
+        ///   the decoded value as a <see cref="string"/>.
+        /// </returns>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <paramref name="encodingType"/> is not a known character string type.
+        /// </exception>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules --OR--
+        ///   the string did not successfully decode
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not the same as
+        ///   <paramref name="encodingType"/>.
+        /// </exception>
+        /// <seealso cref="TryReadPrimitiveCharacterStringBytes(Asn1Tag,UniversalTagNumber,out ReadOnlyMemory{byte})"/>
+        /// <seealso cref="TryCopyCharacterStringBytes(Asn1Tag,UniversalTagNumber,Span{byte},out int)"/>
+        /// <seealso cref="TryCopyCharacterString(Asn1Tag,UniversalTagNumber,Span{char},out int)"/>
+        public string ReadCharacterString(Asn1Tag expectedTag, UniversalTagNumber encodingType)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            string ret = valueReader.ReadCharacterString(expectedTag, encodingType);
+            valueReader.MatchSlice(ref _data);
+            return ret;
+        }
+    }
 }
index f6babd4..4760ebf 100644 (file)
@@ -8,9 +8,8 @@ using System.Diagnostics;
 #nullable enable
 namespace System.Security.Cryptography.Asn1
 {
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
-
         /// <summary>
         ///   Reads the next value as a UTCTime with tag UNIVERSAL 23.
         /// </summary>
@@ -31,7 +30,6 @@ namespace System.Security.Cryptography.Asn1
         public DateTimeOffset ReadUtcTime(int twoDigitYearMax = 2049) =>
             ReadUtcTime(Asn1Tag.UtcTime, twoDigitYearMax);
 
-
         /// <summary>
         ///   Reads the next value as a UTCTime with a specified tag.
         /// </summary>
@@ -72,8 +70,15 @@ namespace System.Security.Cryptography.Asn1
             // T-REC-X.690-201510 sec 11.8
 
             byte[]? rented = null;
-            // The longest format is 17 bytes.
-            Span<byte> tmpSpace = stackalloc byte[17];
+            Span<byte> tmpSpace;
+
+            unsafe
+            {
+                // The longest format is 17 bytes.
+                const int StackBufSize = 17;
+                byte* stackBuf = stackalloc byte[StackBufSize];
+                tmpSpace = new Span<byte>(stackBuf, StackBufSize);
+            }
 
             ReadOnlySpan<byte> contents = GetOctetStringContents(
                 expectedTag,
@@ -224,4 +229,58 @@ namespace System.Security.Cryptography.Asn1
             }
         }
     }
+
+    internal partial class AsnReader
+    {
+        /// <summary>
+        ///   Reads the next value as a UTCTime with tag UNIVERSAL 23.
+        /// </summary>
+        /// <param name="twoDigitYearMax">
+        ///   The largest year to represent with this value.
+        ///   The default value, 2049, represents the 1950-2049 range for X.509 certificates.
+        /// </param>
+        /// <returns>
+        ///   a DateTimeOffset representing the value encoded in the UTCTime.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <seealso cref="System.Globalization.Calendar.TwoDigitYearMax"/>
+        /// <seealso cref="ReadUtcTime(System.Security.Cryptography.Asn1.Asn1Tag,int)"/>
+        public DateTimeOffset ReadUtcTime(int twoDigitYearMax = 2049) =>
+            ReadUtcTime(Asn1Tag.UtcTime, twoDigitYearMax);
+
+        /// <summary>
+        ///   Reads the next value as a UTCTime with a specified tag.
+        /// </summary>
+        /// <param name="expectedTag">The tag to check for before reading.</param>
+        /// <param name="twoDigitYearMax">
+        ///   The largest year to represent with this value.
+        ///   The default value, 2049, represents the 1950-2049 range for X.509 certificates.
+        /// </param>
+        /// <returns>
+        ///   a DateTimeOffset representing the value encoded in the UTCTime.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   the next value does not have the correct tag --OR--
+        ///   the length encoding is not valid under the current encoding rules --OR--
+        ///   the contents are not valid under the current encoding rules
+        /// </exception>
+        /// <exception cref="ArgumentException">
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
+        ///   <see cref="TagClass.Universal"/>, but
+        ///   <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
+        ///   the method
+        /// </exception>
+        /// <seealso cref="System.Globalization.Calendar.TwoDigitYearMax"/>
+        public DateTimeOffset ReadUtcTime(Asn1Tag expectedTag, int twoDigitYearMax = 2049)
+        {
+            AsnValueReader valueReader = OpenValueReader();
+            DateTimeOffset ret = valueReader.ReadUtcTime(expectedTag, twoDigitYearMax);
+            valueReader.MatchSlice(ref _data);
+            return ret;
+        }
+    }
 }
index d733fbf..81bcbfd 100644 (file)
@@ -10,15 +10,15 @@ namespace System.Security.Cryptography.Asn1
     /// <summary>
     ///   A stateful, forward-only reader for BER-, CER-, or DER-encoded ASN.1 data.
     /// </summary>
-    internal partial class AsnReader
+    internal ref partial struct AsnValueReader
     {
         // T-REC-X.690-201508 sec 9.2
         internal const int MaxCERSegmentSize = 1000;
 
         // T-REC-X.690-201508 sec 8.1.5 says only 0000 is legal.
-        private const int EndOfContentsEncodedLength = 2;
+        internal const int EndOfContentsEncodedLength = 2;
 
-        private ReadOnlyMemory<byte> _data;
+        private ReadOnlySpan<byte> _data;
 
         /// <summary>
         ///   The <see cref="AsnEncodingRules"/> in use by this reader.
@@ -31,7 +31,7 @@ namespace System.Security.Cryptography.Asn1
         public bool HasData => !_data.IsEmpty;
 
         /// <summary>
-        ///   Construct an <see cref="AsnReader"/> over <paramref name="data"/> with a given ruleset.
+        ///   Construct an <see cref="AsnValueReader"/> over <paramref name="data"/> with a given ruleset.
         /// </summary>
         /// <param name="data">The data to read.</param>
         /// <param name="ruleSet">The encoding constraints for the reader.</param>
@@ -45,7 +45,7 @@ namespace System.Security.Cryptography.Asn1
         /// <exception cref="ArgumentOutOfRangeException">
         ///   <paramref name="ruleSet"/> is not defined.
         /// </exception>
-        public AsnReader(ReadOnlyMemory<byte> data, AsnEncodingRules ruleSet)
+        public AsnValueReader(ReadOnlySpan<byte> data, AsnEncodingRules ruleSet)
         {
             CheckEncodingRules(ruleSet);
 
@@ -53,6 +53,18 @@ namespace System.Security.Cryptography.Asn1
             RuleSet = ruleSet;
         }
 
+        // Reversed parameter order, to be used by OpenUnchecked.
+        private AsnValueReader(AsnEncodingRules ruleSet, ReadOnlySpan<byte> data)
+        {
+            _data = data;
+            RuleSet = ruleSet;
+        }
+
+        internal static AsnValueReader OpenUnchecked(ReadOnlySpan<byte> data, AsnEncodingRules ruleSet)
+        {
+            return new AsnValueReader(ruleSet, data);
+        }
+
         /// <summary>
         ///   Throws a standardized <see cref="CryptographicException"/> if the reader has remaining
         ///   data, performs no function if <see cref="HasData"/> returns <c>false</c>.
@@ -80,7 +92,7 @@ namespace System.Security.Cryptography.Asn1
         /// </exception>
         public Asn1Tag PeekTag()
         {
-            if (Asn1Tag.TryDecode(_data.Span, out Asn1Tag tag, out int bytesRead))
+            if (Asn1Tag.TryDecode(_data, out Asn1Tag tag, out int bytesRead))
             {
                 return tag;
             }
@@ -89,64 +101,75 @@ namespace System.Security.Cryptography.Asn1
         }
 
         /// <summary>
-        ///   Get a <see cref="ReadOnlyMemory{T}"/> view of the next encoded value without
+        ///   Get a <see cref="ReadOnlySpan{T}"/> view of the next encoded value without
         ///   advancing the reader. For indefinite length encodings this includes the
         ///   End of Contents marker.
         /// </summary>
-        /// <returns>A <see cref="ReadOnlyMemory{T}"/> view of the next encoded value.</returns>
+        /// <returns>A <see cref="ReadOnlySpan{T}"/> view of the next encoded value.</returns>
         /// <exception cref="CryptographicException">
         ///   The reader is positioned at a point where the tag or length is invalid
         ///   under the current encoding rules.
         /// </exception>
         /// <seealso cref="PeekContentBytes"/>
         /// <seealso cref="ReadEncodedValue"/>
-        public ReadOnlyMemory<byte> PeekEncodedValue()
+        public ReadOnlySpan<byte> PeekEncodedValue()
+        {
+            return Slice(_data, 0, GetNextEncodedValueLength());
+        }
+
+        internal int GetNextEncodedValueLength()
         {
             ReadTagAndLength(out int? length, out int bytesRead);
 
             if (length == null)
             {
                 int contentsLength = SeekEndOfContents(_data.Slice(bytesRead));
-                return Slice(_data, 0, bytesRead + contentsLength + EndOfContentsEncodedLength);
+                return bytesRead + contentsLength + AsnReader.EndOfContentsEncodedLength;
             }
 
-            return Slice(_data, 0, bytesRead + length.Value);
+            return bytesRead + length.Value;
         }
 
         /// <summary>
-        ///   Get a <see cref="ReadOnlyMemory{T}"/> view of the content octets (bytes) of the
+        ///   Get a <see cref="ReadOnlySpan{T}"/> view of the content octets (bytes) of the
         ///   next encoded value without advancing the reader.
         /// </summary>
         /// <returns>
-        ///   A <see cref="ReadOnlyMemory{T}"/> view of the contents octets of the next encoded value.
+        ///   A <see cref="ReadOnlySpan{T}"/> view of the contents octets of the next encoded value.
         /// </returns>
         /// <exception cref="CryptographicException">
         ///   The reader is positioned at a point where the tag or length is invalid
         ///   under the current encoding rules.
         /// </exception>
         /// <seealso cref="PeekEncodedValue"/>
-        public ReadOnlyMemory<byte> PeekContentBytes()
+        public ReadOnlySpan<byte> PeekContentBytes()
+        {
+            (int offset, int length) = GetNextContentRange();
+            return Slice(_data, offset, length);
+        }
+
+        internal (int Offset, int Length) GetNextContentRange()
         {
             ReadTagAndLength(out int? length, out int bytesRead);
 
             if (length == null)
             {
-                return Slice(_data, bytesRead, SeekEndOfContents(_data.Slice(bytesRead)));
+                return (bytesRead, SeekEndOfContents(_data.Slice(bytesRead)));
             }
 
-            return Slice(_data, bytesRead, length.Value);
+            return (bytesRead, length.Value);
         }
 
         /// <summary>
-        ///   Get a <see cref="ReadOnlyMemory{T}"/> view of the next encoded value,
+        ///   Get a <see cref="ReadOnlySpan{T}"/> view of the next encoded value,
         ///   and advance the reader past it. For an indefinite length encoding this includes
         ///   the End of Contents marker.
         /// </summary>
-        /// <returns>A <see cref="ReadOnlyMemory{T}"/> view of the next encoded value.</returns>
+        /// <returns>A <see cref="ReadOnlySpan{T}"/> view of the next encoded value.</returns>
         /// <seealso cref="PeekEncodedValue"/>
-        public ReadOnlyMemory<byte> ReadEncodedValue()
+        public ReadOnlySpan<byte> ReadEncodedValue()
         {
-            ReadOnlyMemory<byte> encodedValue = PeekEncodedValue();
+            ReadOnlySpan<byte> encodedValue = PeekEncodedValue();
             _data = _data.Slice(encodedValue.Length);
             return encodedValue;
         }
@@ -160,7 +183,7 @@ namespace System.Security.Cryptography.Asn1
             length = null;
             bytesRead = 0;
 
-            CheckEncodingRules(ruleSet);
+            AssertEncodingRules(ruleSet);
 
             if (source.IsEmpty)
             {
@@ -278,8 +301,8 @@ namespace System.Security.Cryptography.Asn1
 
         internal Asn1Tag ReadTagAndLength(out int? contentsLength, out int bytesRead)
         {
-            if (Asn1Tag.TryDecode(_data.Span, out Asn1Tag tag, out int tagBytesRead) &&
-                TryReadLength(_data.Slice(tagBytesRead).Span, RuleSet, out int? length, out int lengthBytesRead))
+            if (Asn1Tag.TryDecode(_data, out Asn1Tag tag, out int tagBytesRead) &&
+                TryReadLength(_data.Slice(tagBytesRead), RuleSet, out int? length, out int lengthBytesRead))
             {
                 int allBytesRead = tagBytesRead + lengthBytesRead;
 
@@ -318,12 +341,21 @@ namespace System.Security.Cryptography.Asn1
         /// Get the number of bytes between the start of <paramref name="source" /> and
         /// the End-of-Contents marker
         /// </summary>
-        private int SeekEndOfContents(ReadOnlyMemory<byte> source)
+        private int SeekEndOfContents(ReadOnlySpan<byte> source)
+        {
+            return SeekEndOfContents(source, RuleSet);
+        }
+
+        /// <summary>
+        /// Get the number of bytes between the start of <paramref name="source" /> and
+        /// the End-of-Contents marker
+        /// </summary>
+        internal static int SeekEndOfContents(ReadOnlySpan<byte> source, AsnEncodingRules ruleSet)
         {
-            ReadOnlyMemory<byte> cur = source;
+            ReadOnlySpan<byte> cur = source;
             int totalLen = 0;
 
-            AsnReader tmpReader = new AsnReader(cur, RuleSet);
+            AsnValueReader tmpReader = OpenUnchecked(cur, ruleSet);
             // Our reader is bounded by int.MaxValue.
             // The most aggressive data input would be a one-byte tag followed by
             // indefinite length "ad infinitum", which would be half the input.
@@ -361,7 +393,7 @@ namespace System.Security.Cryptography.Asn1
                 else
                 {
                     // This will throw a CryptographicException if the length exceeds our bounds.
-                    ReadOnlyMemory<byte> tlv = Slice(tmpReader._data, 0, bytesRead + length.Value);
+                    ReadOnlySpan<byte> tlv = Slice(tmpReader._data, 0, bytesRead + length.Value);
 
                     // No exception? Then slice the data and continue.
                     tmpReader._data = tmpReader._data.Slice(tlv.Length);
@@ -380,7 +412,7 @@ namespace System.Security.Cryptography.Asn1
             return value;
         }
 
-        private static int ParseNonNegativeInt(ReadOnlySpan<byte> data)
+        internal static int ParseNonNegativeInt(ReadOnlySpan<byte> data)
         {
             if (Utf8Parser.TryParse(data, out uint value, out int consumed) &&
                 value <= int.MaxValue &&
@@ -410,7 +442,7 @@ namespace System.Security.Cryptography.Asn1
             return source.Slice(offset, length);
         }
 
-        private static ReadOnlyMemory<byte> Slice(ReadOnlyMemory<byte> source, int offset, int? length)
+        private static ReadOnlySpan<byte> Slice(ReadOnlySpan<byte> source, int offset, int? length)
         {
             Debug.Assert(offset >= 0);
 
@@ -429,7 +461,40 @@ namespace System.Security.Cryptography.Asn1
             return source.Slice(offset, lengthVal);
         }
 
-        private static void CheckEncodingRules(AsnEncodingRules ruleSet)
+        internal static ReadOnlyMemory<byte> Slice(ReadOnlyMemory<byte> bigger, ReadOnlySpan<byte> smaller)
+        {
+            if (smaller.IsEmpty)
+            {
+                return default;
+            }
+
+            if (bigger.Span.Overlaps(smaller, out int offset))
+            {
+                return bigger.Slice(offset, smaller.Length);
+            }
+
+            Debug.Fail("AsnReader asked for a matching slice from a non-overlapping input");
+            throw new CryptographicException();
+        }
+
+        /// <summary>
+        ///   Slices <paramref name="memory"/> to represent the same data this reader value has.
+        /// </summary>
+        /// <exception cref="CryptographicException">
+        ///   <paramref name="memory"/> does not represent a super-range of the data this reader is processing.
+        /// </exception>
+        internal void MatchSlice(ref ReadOnlyMemory<byte> memory)
+        {
+            memory = Slice(memory, _data);
+        }
+
+        [Conditional("DEBUG")]
+        private static void AssertEncodingRules(AsnEncodingRules ruleSet)
+        {
+            Debug.Assert(ruleSet >= AsnEncodingRules.BER && ruleSet <= AsnEncodingRules.DER);
+        }
+
+        internal static void CheckEncodingRules(AsnEncodingRules ruleSet)
         {
             if (ruleSet != AsnEncodingRules.BER &&
                 ruleSet != AsnEncodingRules.CER &&
@@ -439,7 +504,7 @@ namespace System.Security.Cryptography.Asn1
             }
         }
 
-        private static void CheckExpectedTag(Asn1Tag tag, Asn1Tag expectedTag, UniversalTagNumber tagNumber)
+        internal static void CheckExpectedTag(Asn1Tag tag, Asn1Tag expectedTag, UniversalTagNumber tagNumber)
         {
             if (expectedTag.TagClass == TagClass.Universal && expectedTag.TagValue != (int)tagNumber)
             {
@@ -454,4 +519,157 @@ namespace System.Security.Cryptography.Asn1
             }
         }
     }
+
+    /// <summary>
+    ///   A stateful, forward-only reader for BER-, CER-, or DER-encoded ASN.1 data.
+    /// </summary>
+    internal partial class AsnReader
+    {
+        internal const int MaxCERSegmentSize = AsnValueReader.MaxCERSegmentSize;
+        internal const int EndOfContentsEncodedLength = AsnValueReader.EndOfContentsEncodedLength;
+
+        private ReadOnlyMemory<byte> _data;
+
+        /// <summary>
+        ///   The <see cref="AsnEncodingRules"/> in use by this reader.
+        /// </summary>
+        public AsnEncodingRules RuleSet { get; }
+
+        /// <summary>
+        ///   An indication of whether or not the reader has remaining data available to process.
+        /// </summary>
+        public bool HasData => !_data.IsEmpty;
+
+        /// <summary>
+        ///   Construct an <see cref="AsnReader"/> over <paramref name="data"/> with a given ruleset.
+        /// </summary>
+        /// <param name="data">The data to read.</param>
+        /// <param name="ruleSet">The encoding constraints for the reader.</param>
+        /// <remarks>
+        ///   This constructor does not evaluate <paramref name="data"/> for correctness,
+        ///   any correctness checks are done as part of member methods.
+        ///
+        ///   This constructor does not copy <paramref name="data"/>. The caller is responsible for
+        ///   ensuring that the values do not change until the reader is finished.
+        /// </remarks>
+        /// <exception cref="ArgumentOutOfRangeException">
+        ///   <paramref name="ruleSet"/> is not defined.
+        /// </exception>
+        public AsnReader(ReadOnlyMemory<byte> data, AsnEncodingRules ruleSet)
+        {
+            AsnValueReader.CheckEncodingRules(ruleSet);
+
+            _data = data;
+            RuleSet = ruleSet;
+        }
+
+        /// <summary>
+        ///   Throws a standardized <see cref="CryptographicException"/> if the reader has remaining
+        ///   data, performs no function if <see cref="HasData"/> returns <c>false</c>.
+        /// </summary>
+        /// <remarks>
+        ///   This method provides a standardized target and standardized exception for reading a
+        ///   "closed" structure, such as the nested content for an explicitly tagged value.
+        /// </remarks>
+        public void ThrowIfNotEmpty()
+        {
+            if (HasData)
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+        }
+
+        /// <summary>
+        ///   Read the encoded tag at the next data position, without advancing the reader.
+        /// </summary>
+        /// <returns>
+        ///   The decoded <see cref="Asn1Tag"/> value.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   a tag could not be decoded at the reader's current position.
+        /// </exception>
+        public Asn1Tag PeekTag()
+        {
+            if (Asn1Tag.TryDecode(_data.Span, out Asn1Tag tag, out int bytesRead))
+            {
+                return tag;
+            }
+
+            throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+        }
+
+        private AsnValueReader OpenValueReader()
+        {
+            return AsnValueReader.OpenUnchecked(_data.Span, RuleSet);
+        }
+
+        /// <summary>
+        ///   Get a <see cref="ReadOnlyMemory{T}"/> view of the next encoded value without
+        ///   advancing the reader. For indefinite length encodings this includes the
+        ///   End of Contents marker.
+        /// </summary>
+        /// <returns>A <see cref="ReadOnlyMemory{T}"/> view of the next encoded value.</returns>
+        /// <exception cref="CryptographicException">
+        ///   The reader is positioned at a point where the tag or length is invalid
+        ///   under the current encoding rules.
+        /// </exception>
+        /// <seealso cref="PeekContentBytes"/>
+        /// <seealso cref="ReadEncodedValue"/>
+        public ReadOnlyMemory<byte> PeekEncodedValue()
+        {
+            AsnValueReader reader = OpenValueReader();
+            return Slice(_data, 0, reader.GetNextEncodedValueLength());
+        }
+
+        /// <summary>
+        ///   Get a <see cref="ReadOnlyMemory{T}"/> view of the content octets (bytes) of the
+        ///   next encoded value without advancing the reader.
+        /// </summary>
+        /// <returns>
+        ///   A <see cref="ReadOnlyMemory{T}"/> view of the contents octets of the next encoded value.
+        /// </returns>
+        /// <exception cref="CryptographicException">
+        ///   The reader is positioned at a point where the tag or length is invalid
+        ///   under the current encoding rules.
+        /// </exception>
+        /// <seealso cref="PeekEncodedValue"/>
+        public ReadOnlyMemory<byte> PeekContentBytes()
+        {
+            AsnValueReader reader = OpenValueReader();
+            (int offset, int length) = reader.GetNextContentRange();
+            return Slice(_data, offset, length);
+        }
+
+        /// <summary>
+        ///   Get a <see cref="ReadOnlyMemory{T}"/> view of the next encoded value,
+        ///   and advance the reader past it. For an indefinite length encoding this includes
+        ///   the End of Contents marker.
+        /// </summary>
+        /// <returns>A <see cref="ReadOnlyMemory{T}"/> view of the next encoded value.</returns>
+        /// <seealso cref="PeekEncodedValue"/>
+        public ReadOnlyMemory<byte> ReadEncodedValue()
+        {
+            ReadOnlyMemory<byte> encodedValue = PeekEncodedValue();
+            _data = _data.Slice(encodedValue.Length);
+            return encodedValue;
+        }
+
+        internal Asn1Tag ReadTagAndLength(out int? contentsLength, out int bytesRead)
+        {
+            AsnValueReader reader = OpenValueReader();
+            return reader.ReadTagAndLength(out contentsLength, out bytesRead);
+        }
+
+        private static ReadOnlyMemory<byte> Slice(ReadOnlyMemory<byte> source, int offset, int length)
+        {
+            Debug.Assert(offset >= 0);
+
+            if (length < 0 || source.Length - offset < length)
+            {
+                throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
+            }
+
+            return source.Slice(offset, length);
+        }
+    }
 }
index 6f87171..ad9a9b8 100644 (file)
@@ -10,18 +10,18 @@ namespace System.Security.Cryptography.Asn1
     {
         internal static SetOfValueComparer Instance { get; } = new SetOfValueComparer();
 
-        public int Compare(ReadOnlyMemory<byte> x, ReadOnlyMemory<byte> y)
-        {
-            ReadOnlySpan<byte> xSpan = x.Span;
-            ReadOnlySpan<byte> ySpan = y.Span;
+        public int Compare(ReadOnlyMemory<byte> x, ReadOnlyMemory<byte> y) =>
+            Compare(x.Span, y.Span);
 
+        internal static int Compare(ReadOnlySpan<byte> x, ReadOnlySpan<byte> y)
+        {
             int min = Math.Min(x.Length, y.Length);
             int diff;
 
             for (int i = 0; i < min; i++)
             {
-                int xVal = xSpan[i];
-                byte yVal = ySpan[i];
+                int xVal = x[i];
+                byte yVal = y[i];
                 diff = xVal - yVal;
 
                 if (diff != 0)
index d1b5d68..2647c35 100644 (file)
@@ -36,9 +36,9 @@ namespace System.Security.Cryptography
             out int bytesRead)
         {
             // X.509 SubjectPublicKeyInfo is described as DER.
-            AsnReader reader = new AsnReader(source, AsnEncodingRules.DER);
+            AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.DER);
             int read = reader.PeekEncodedValue().Length;
-            SubjectPublicKeyInfoAsn.Decode(reader, out SubjectPublicKeyInfoAsn spki);
+            SubjectPublicKeyInfoAsn.Decode(ref reader, source, out SubjectPublicKeyInfoAsn spki);
 
             if (Array.IndexOf(validOids, spki.Algorithm.Algorithm.Value) < 0)
             {
@@ -57,9 +57,9 @@ namespace System.Security.Cryptography
             out TRet ret)
         {
             // X.509 SubjectPublicKeyInfo is described as DER.
-            AsnReader reader = new AsnReader(source, AsnEncodingRules.DER);
+            AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.DER);
             int read = reader.PeekEncodedValue().Length;
-            SubjectPublicKeyInfoAsn.Decode(reader, out SubjectPublicKeyInfoAsn spki);
+            SubjectPublicKeyInfoAsn.Decode(ref reader, source, out SubjectPublicKeyInfoAsn spki);
 
             if (Array.IndexOf(validOids, spki.Algorithm.Algorithm.Value) < 0)
             {
@@ -91,9 +91,9 @@ namespace System.Security.Cryptography
             ReadOnlyMemory<byte> source,
             out int bytesRead)
         {
-            AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+            AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.BER);
             int read = reader.PeekEncodedValue().Length;
-            PrivateKeyInfoAsn.Decode(reader, out PrivateKeyInfoAsn privateKeyInfo);
+            PrivateKeyInfoAsn.Decode(ref reader, source, out PrivateKeyInfoAsn privateKeyInfo);
 
             if (Array.IndexOf(validOids, privateKeyInfo.PrivateKeyAlgorithm.Algorithm.Value) < 0)
             {
@@ -111,9 +111,9 @@ namespace System.Security.Cryptography
             out int bytesRead,
             out TRet ret)
         {
-            AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+            AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.BER);
             int read = reader.PeekEncodedValue().Length;
-            PrivateKeyInfoAsn.Decode(reader, out PrivateKeyInfoAsn privateKeyInfo);
+            PrivateKeyInfoAsn.Decode(ref reader, source, out PrivateKeyInfoAsn privateKeyInfo);
 
             if (Array.IndexOf(validOids, privateKeyInfo.PrivateKeyAlgorithm.Algorithm.Value) < 0)
             {
@@ -204,9 +204,9 @@ namespace System.Security.Cryptography
             out int bytesRead,
             out TRet ret)
         {
-            AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+            AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.BER);
             int read = reader.PeekEncodedValue().Length;
-            EncryptedPrivateKeyInfoAsn.Decode(reader, out EncryptedPrivateKeyInfoAsn epki);
+            EncryptedPrivateKeyInfoAsn.Decode(ref reader, source, out EncryptedPrivateKeyInfoAsn epki);
 
             // No supported encryption algorithms produce more bytes of decryption output than there
             // were of decryption input.
@@ -422,9 +422,9 @@ namespace System.Security.Cryptography
             ReadOnlyMemory<byte> source,
             out int bytesRead)
         {
-            AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+            AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.BER);
             int localRead = reader.PeekEncodedValue().Length;
-            EncryptedPrivateKeyInfoAsn.Decode(reader, out EncryptedPrivateKeyInfoAsn epki);
+            EncryptedPrivateKeyInfoAsn.Decode(ref reader, source, out EncryptedPrivateKeyInfoAsn epki);
 
             // No supported encryption algorithms produce more bytes of decryption output than there
             // were of decryption input.
index c27fc6c..99440d9 100644 (file)
@@ -48,14 +48,14 @@ namespace Internal.Cryptography
             try
             {
                 StringBuilder output = new StringBuilder();
-                AsnReader reader = new AsnReader(rawData, AsnEncodingRules.DER);
-                AsnReader collectionReader = reader.ReadSequence();
+                AsnValueReader reader = new AsnValueReader(rawData, AsnEncodingRules.DER);
+                AsnValueReader collectionReader = reader.ReadSequence();
 
                 reader.ThrowIfNotEmpty();
 
                 while (collectionReader.HasData)
                 {
-                    GeneralNameAsn.Decode(collectionReader, out GeneralNameAsn generalName);
+                    GeneralNameAsn.Decode(ref collectionReader, rawData, out GeneralNameAsn generalName);
 
                     if (output.Length != 0)
                     {
index f09e920..1ed4370 100644 (file)
@@ -210,5 +210,45 @@ namespace System.Security.Cryptography.Tests.Asn1
             Assert.Equal(expectedLength, contents.Length);
             Assert.True(Unsafe.AreSame(ref dataBytes[0], ref MemoryMarshal.GetReference(contents.Span)));
         }
+
+        [Fact]
+        public static void PeekEncodedValue_InvalidLength()
+        {
+            byte[] badLength = "04040203".HexToByteArray();
+
+            AsnReader reader = new AsnReader(badLength, AsnEncodingRules.BER);
+
+            Assert.Throws<CryptographicException>(() => reader.PeekEncodedValue());
+            Assert.Throws<CryptographicException>(() => reader.ReadEncodedValue());
+
+            Assert.Throws<CryptographicException>(
+                () =>
+                {
+                    AsnValueReader valueReader = new AsnValueReader(badLength, AsnEncodingRules.BER);
+                    valueReader.PeekEncodedValue();
+                });
+            Assert.Throws<CryptographicException>(
+                () =>
+                {
+                    AsnValueReader valueReader = new AsnValueReader(badLength, AsnEncodingRules.BER);
+                    valueReader.ReadEncodedValue();
+                });
+        }
+
+        [Fact]
+        public static void PeekContentBytes_InvalidLength()
+        {
+            byte[] badLength = "04040203".HexToByteArray();
+
+            AsnReader reader = new AsnReader(badLength, AsnEncodingRules.BER);
+
+            Assert.Throws<CryptographicException>(() => reader.PeekContentBytes());
+            Assert.Throws<CryptographicException>(
+                () =>
+                {
+                    AsnValueReader valueReader = new AsnValueReader(badLength, AsnEncodingRules.BER);
+                    valueReader.PeekContentBytes();
+                });
+        }
     }
 }
index 3b93c13..8ff87d1 100644 (file)
@@ -196,19 +196,31 @@ namespace System.Security.Cryptography.Tests.Asn1
             int tagValue)
         {
             byte[] inputData = inputHex.HexToByteArray();
+            Asn1Tag constructedTag = new Asn1Tag((TagClass)tagClass, tagValue, true);
+            Asn1Tag primitiveTag = new Asn1Tag((TagClass)tagClass, tagValue, false);
             AsnReader reader = new AsnReader(inputData, (AsnEncodingRules)ruleSet);
 
-            string val1 = reader.ReadObjectIdentifierAsString(new Asn1Tag((TagClass)tagClass, tagValue, true));
+            string val1 = reader.ReadObjectIdentifierAsString(constructedTag);
+            Assert.False(reader.HasData);
+
+            reader = new AsnReader(inputData, (AsnEncodingRules)ruleSet);
 
+            Oid oid1 = reader.ReadObjectIdentifier(constructedTag);
             Assert.False(reader.HasData);
 
             reader = new AsnReader(inputData, (AsnEncodingRules)ruleSet);
 
-            string val2 = reader.ReadObjectIdentifierAsString(new Asn1Tag((TagClass)tagClass, tagValue, false));
+            string val2 = reader.ReadObjectIdentifierAsString(primitiveTag);
+            Assert.False(reader.HasData);
+
+            reader = new AsnReader(inputData, (AsnEncodingRules)ruleSet);
 
+            Oid oid2 = reader.ReadObjectIdentifier(primitiveTag);
             Assert.False(reader.HasData);
 
             Assert.Equal(val1, val2);
+            Assert.Equal(oid1.Value, oid2.Value);
+            Assert.Equal(oid1.Value, val1);
         }
 
         [Theory]
index 0c4bcdb..e39d35f 100644 (file)
@@ -13,9 +13,9 @@ namespace Internal.Cryptography.Pal.AnyOS
     {
         public override Oid GetEncodedMessageType(byte[] encodedMessage)
         {
-            AsnReader reader = new AsnReader(encodedMessage, AsnEncodingRules.BER);
+            AsnValueReader reader = new AsnValueReader(encodedMessage, AsnEncodingRules.BER);
 
-            ContentInfoAsn.Decode(reader, out ContentInfoAsn contentInfo);
+            ContentInfoAsn.Decode(ref reader, encodedMessage, out ContentInfoAsn contentInfo);
 
             switch (contentInfo.ContentType)
             {
index a8a0dac..dea5107 100644 (file)
@@ -25,10 +25,11 @@ namespace Internal.Cryptography.Pal.AnyOS
             out CryptographicAttributeObjectCollection unprotectedAttributes)
         {
             // Read using BER because the CMS specification says the encoding is BER.
-            AsnReader reader = new AsnReader(encodedMessage, AsnEncodingRules.BER);
+            AsnValueReader reader = new AsnValueReader(encodedMessage, AsnEncodingRules.BER);
 
             ContentInfoAsn.Decode(
-                reader,
+                ref reader,
+                encodedMessage,
                 out ContentInfoAsn parsedContentInfo);
 
             if (parsedContentInfo.ContentType != Oids.Pkcs7Enveloped)
index 824a7e7..cb330c8 100644 (file)
@@ -139,13 +139,13 @@ namespace Internal.Cryptography
                 }
             }
 
-            AsnReader reader = new AsnReader(normalizedValue, AsnEncodingRules.DER);
-            AsnReader setReader = reader.ReadSetOf();
+            AsnValueReader reader = new AsnValueReader(normalizedValue, AsnEncodingRules.DER);
+            AsnValueReader setReader = reader.ReadSetOf();
             AttributeAsn[] decodedSet = new AttributeAsn[setItems.Length];
             int i = 0;
             while (setReader.HasData)
             {
-                AttributeAsn.Decode(setReader, out AttributeAsn item);
+                AttributeAsn.Decode(ref setReader, normalizedValue, out AttributeAsn item);
                 decodedSet[i] = item;
                 i++;
             }
index 17bb9c7..fc9cf83 100644 (file)
@@ -16,21 +16,21 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal System.Security.Cryptography.Asn1.GeneralNameAsn[] Issuer;
         internal ReadOnlyMemory<byte> SerialNumber;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
 
             writer.PushSequence();
             for (int i = 0; i < Issuer.Length; i++)
             {
-                Issuer[i].Encode(writer); 
+                Issuer[i].Encode(writer);
             }
             writer.PopSequence();
 
@@ -42,33 +42,30 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static CadesIssuerSerial Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out CadesIssuerSerial decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out CadesIssuerSerial decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out CadesIssuerSerial decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out CadesIssuerSerial decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CadesIssuerSerial decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out CadesIssuerSerial decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             // Decode SEQUENCE OF for Issuer
             {
@@ -78,14 +75,15 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                 while (collectionReader.HasData)
                 {
-                    System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(collectionReader, out tmpItem); 
+                    System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(ref collectionReader, rebind, out tmpItem);
                     tmpList.Add(tmpItem);
                 }
 
                 decoded.Issuer = tmpList.ToArray();
             }
 
-            decoded.SerialNumber = sequenceReader.ReadIntegerBytes();
+            tmpSpan = sequenceReader.ReadIntegerBytes();
+            decoded.SerialNumber = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
 
             sequenceReader.ThrowIfNotEmpty();
         }
index 72563e7..3c6c362 100644 (file)
@@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Asn1;
 
+#nullable enable
 namespace System.Security.Cryptography.Pkcs.Asn1
 {
     [StructLayout(LayoutKind.Sequential)]
@@ -21,27 +22,27 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
             Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
             {
-                if (usedTags.TryGetValue(tag, out string existing))
+                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((UniversalTagNumber)16), "Certificate");
         }
 #endif
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            bool wroteValue = false;
+
             if (Certificate.HasValue)
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 // Validator for tag constraint for Certificate
                 {
                     if (!Asn1Tag.TryDecode(Certificate.Value.Span, out Asn1Tag validateTag, out _) ||
@@ -63,24 +64,25 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
         internal static CertificateChoiceAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out CertificateChoiceAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out CertificateChoiceAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out CertificateChoiceAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out CertificateChoiceAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             if (tag.HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16)))
             {
-                decoded.Certificate = reader.ReadEncodedValue();
+                tmpSpan = reader.ReadEncodedValue();
+                decoded.Certificate = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index b4d147d..e80e5dd 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal string ContentType;
         internal ReadOnlyMemory<byte>? Content;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteObjectIdentifier(ContentType);
 
             if (Content.HasValue)
@@ -41,39 +41,37 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static EncapsulatedContentInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out EncapsulatedContentInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out EncapsulatedContentInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out EncapsulatedContentInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out EncapsulatedContentInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EncapsulatedContentInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out EncapsulatedContentInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.ContentType = sequenceReader.ReadObjectIdentifierAsString();
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
                 explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
-                decoded.Content = explicitReader.ReadEncodedValue();
+                tmpSpan = explicitReader.ReadEncodedValue();
+                decoded.Content = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 explicitReader.ThrowIfNotEmpty();
             }
 
index e1dcb2c..005d78a 100644 (file)
@@ -19,16 +19,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         internal System.Security.Cryptography.Pkcs.Asn1.RecipientInfoAsn[] RecipientInfos;
         internal System.Security.Cryptography.Asn1.Pkcs7.EncryptedContentInfoAsn EncryptedContentInfo;
         internal System.Security.Cryptography.Asn1.AttributeAsn[] UnprotectedAttributes;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Version);
 
             if (OriginatorInfo.HasValue)
@@ -40,7 +40,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             writer.PushSetOf();
             for (int i = 0; i < RecipientInfos.Length; i++)
             {
-                RecipientInfos[i].Encode(writer); 
+                RecipientInfos[i].Encode(writer);
             }
             writer.PopSetOf();
 
@@ -52,7 +52,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
                 for (int i = 0; i < UnprotectedAttributes.Length; i++)
                 {
-                    UnprotectedAttributes[i].Encode(writer); 
+                    UnprotectedAttributes[i].Encode(writer);
                 }
                 writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
 
@@ -65,33 +65,27 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static EnvelopedDataAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out EnvelopedDataAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out EnvelopedDataAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out EnvelopedDataAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out EnvelopedDataAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EnvelopedDataAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out EnvelopedDataAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader collectionReader;
+
 
             if (!sequenceReader.TryReadInt32(out decoded.Version))
             {
@@ -102,7 +96,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
                 System.Security.Cryptography.Pkcs.Asn1.OriginatorInfoAsn tmpOriginatorInfo;
-                System.Security.Cryptography.Pkcs.Asn1.OriginatorInfoAsn.Decode(sequenceReader, new Asn1Tag(TagClass.ContextSpecific, 0), out tmpOriginatorInfo);
+                System.Security.Cryptography.Pkcs.Asn1.OriginatorInfoAsn.Decode(ref sequenceReader, new Asn1Tag(TagClass.ContextSpecific, 0), rebind, out tmpOriginatorInfo);
                 decoded.OriginatorInfo = tmpOriginatorInfo;
 
             }
@@ -116,14 +110,14 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                 while (collectionReader.HasData)
                 {
-                    System.Security.Cryptography.Pkcs.Asn1.RecipientInfoAsn.Decode(collectionReader, out tmpItem); 
+                    System.Security.Cryptography.Pkcs.Asn1.RecipientInfoAsn.Decode(ref collectionReader, rebind, out tmpItem);
                     tmpList.Add(tmpItem);
                 }
 
                 decoded.RecipientInfos = tmpList.ToArray();
             }
 
-            System.Security.Cryptography.Asn1.Pkcs7.EncryptedContentInfoAsn.Decode(sequenceReader, out decoded.EncryptedContentInfo);
+            System.Security.Cryptography.Asn1.Pkcs7.EncryptedContentInfoAsn.Decode(ref sequenceReader, rebind, out decoded.EncryptedContentInfo);
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
             {
@@ -136,7 +130,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index 9d8843e..d5e2095 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal ReadOnlyMemory<byte> Hash;
         internal System.Security.Cryptography.Pkcs.Asn1.CadesIssuerSerial? IssuerSerial;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteOctetString(Hash.Span);
 
             if (IssuerSerial.HasValue)
@@ -39,36 +39,33 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static EssCertId Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out EssCertId decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out EssCertId decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out EssCertId decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out EssCertId decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EssCertId decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out EssCertId decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpHash))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.Hash = tmpHash;
+                decoded.Hash = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
@@ -79,7 +76,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
             {
                 System.Security.Cryptography.Pkcs.Asn1.CadesIssuerSerial tmpIssuerSerial;
-                System.Security.Cryptography.Pkcs.Asn1.CadesIssuerSerial.Decode(sequenceReader, out tmpIssuerSerial);
+                System.Security.Cryptography.Pkcs.Asn1.CadesIssuerSerial.Decode(ref sequenceReader, rebind, out tmpIssuerSerial);
                 decoded.IssuerSerial = tmpIssuerSerial;
 
             }
index be20b78..cfff6e4 100644 (file)
@@ -14,33 +14,34 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     internal partial struct EssCertIdV2
     {
         private static readonly byte[] s_defaultHashAlgorithm = { 0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01 };
-  
+
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm;
         internal ReadOnlyMemory<byte> Hash;
         internal System.Security.Cryptography.Pkcs.Asn1.CadesIssuerSerial? IssuerSerial;
-      
+
 #if DEBUG
         static EssCertIdV2()
         {
             EssCertIdV2 decoded = default;
-            AsnReader reader;
+            ReadOnlyMemory<byte> rebind = default;
+            AsnValueReader reader;
 
-            reader = new AsnReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.HashAlgorithm);
+            reader = new AsnValueReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashAlgorithm);
             reader.ThrowIfNotEmpty();
         }
 #endif
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
-        
+
+
             // DEFAULT value handler for HashAlgorithm.
             {
                 using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
@@ -50,7 +51,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     if (!encoded.SequenceEqual(s_defaultHashAlgorithm))
                     {
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                     }
                 }
             }
@@ -69,48 +70,45 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static EssCertIdV2 Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out EssCertIdV2 decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out EssCertIdV2 decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out EssCertIdV2 decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out EssCertIdV2 decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EssCertIdV2 decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out EssCertIdV2 decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader defaultReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader defaultReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
             {
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.HashAlgorithm);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.HashAlgorithm);
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
-                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.HashAlgorithm);
+                defaultReader = new AsnValueReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
+                System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.HashAlgorithm);
             }
 
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpHash))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.Hash = tmpHash;
+                decoded.Hash = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
@@ -121,7 +119,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
             {
                 System.Security.Cryptography.Pkcs.Asn1.CadesIssuerSerial tmpIssuerSerial;
-                System.Security.Cryptography.Pkcs.Asn1.CadesIssuerSerial.Decode(sequenceReader, out tmpIssuerSerial);
+                System.Security.Cryptography.Pkcs.Asn1.CadesIssuerSerial.Decode(ref sequenceReader, rebind, out tmpIssuerSerial);
                 decoded.IssuerSerial = tmpIssuerSerial;
 
             }
index 841a0f8..3077daa 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal ReadOnlyMemory<byte> Issuer;
         internal ReadOnlyMemory<byte> SerialNumber;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             // Validator for tag constraint for Issuer
             {
                 if (!Asn1Tag.TryDecode(Issuer.Span, out Asn1Tag validateTag, out _) ||
@@ -43,39 +43,38 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static IssuerAndSerialNumberAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out IssuerAndSerialNumberAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out IssuerAndSerialNumberAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out IssuerAndSerialNumberAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out IssuerAndSerialNumberAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out IssuerAndSerialNumberAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out IssuerAndSerialNumberAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             if (!sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16)))
             {
                 throw new CryptographicException();
             }
 
-            decoded.Issuer = sequenceReader.ReadEncodedValue();
-            decoded.SerialNumber = sequenceReader.ReadIntegerBytes();
+            tmpSpan = sequenceReader.ReadEncodedValue();
+            decoded.Issuer = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
+            tmpSpan = sequenceReader.ReadIntegerBytes();
+            decoded.SerialNumber = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
 
             sequenceReader.ThrowIfNotEmpty();
         }
index faa5e0b..35b70d8 100644 (file)
@@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Asn1;
 
+#nullable enable
 namespace System.Security.Cryptography.Pkcs.Asn1
 {
     [StructLayout(LayoutKind.Sequential)]
@@ -22,14 +23,14 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
             Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
             {
-                if (usedTags.TryGetValue(tag, out string existing))
+                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(Asn1Tag.Sequence, "IssuerAndSerialNumber");
             ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "RKeyId");
         }
@@ -37,13 +38,13 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            bool wroteValue = false;
+
             if (IssuerAndSerialNumber.HasValue)
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 IssuerAndSerialNumber.Value.Encode(writer);
                 wroteValue = true;
             }
@@ -52,7 +53,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 RKeyId.Value.Encode(writer, new Asn1Tag(TagClass.ContextSpecific, 0));
                 wroteValue = true;
             }
@@ -65,32 +66,29 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
         internal static KeyAgreeRecipientIdentifierAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out KeyAgreeRecipientIdentifierAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out KeyAgreeRecipientIdentifierAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out KeyAgreeRecipientIdentifierAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out KeyAgreeRecipientIdentifierAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            
+
             if (tag.HasSameClassAndValue(Asn1Tag.Sequence))
             {
                 System.Security.Cryptography.Pkcs.Asn1.IssuerAndSerialNumberAsn tmpIssuerAndSerialNumber;
-                System.Security.Cryptography.Pkcs.Asn1.IssuerAndSerialNumberAsn.Decode(reader, out tmpIssuerAndSerialNumber);
+                System.Security.Cryptography.Pkcs.Asn1.IssuerAndSerialNumberAsn.Decode(ref reader, rebind, out tmpIssuerAndSerialNumber);
                 decoded.IssuerAndSerialNumber = tmpIssuerAndSerialNumber;
 
             }
             else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
                 System.Security.Cryptography.Pkcs.Asn1.RecipientKeyIdentifier tmpRKeyId;
-                System.Security.Cryptography.Pkcs.Asn1.RecipientKeyIdentifier.Decode(reader, new Asn1Tag(TagClass.ContextSpecific, 0), out tmpRKeyId);
+                System.Security.Cryptography.Pkcs.Asn1.RecipientKeyIdentifier.Decode(ref reader, new Asn1Tag(TagClass.ContextSpecific, 0), rebind, out tmpRKeyId);
                 decoded.RKeyId = tmpRKeyId;
 
             }
index 70dd55f..012c59d 100644 (file)
@@ -19,16 +19,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         internal ReadOnlyMemory<byte>? Ukm;
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn KeyEncryptionAlgorithm;
         internal System.Security.Cryptography.Pkcs.Asn1.RecipientEncryptedKeyAsn[] RecipientEncryptedKeys;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Version);
             writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
             Originator.Encode(writer);
@@ -46,7 +46,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             writer.PushSequence();
             for (int i = 0; i < RecipientEncryptedKeys.Length; i++)
             {
-                RecipientEncryptedKeys[i].Encode(writer); 
+                RecipientEncryptedKeys[i].Encode(writer);
             }
             writer.PopSequence();
 
@@ -57,34 +57,31 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static KeyAgreeRecipientInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out KeyAgreeRecipientInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out KeyAgreeRecipientInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out KeyAgreeRecipientInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out KeyAgreeRecipientInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out KeyAgreeRecipientInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out KeyAgreeRecipientInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (!sequenceReader.TryReadInt32(out decoded.Version))
             {
@@ -93,7 +90,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
 
             explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
-            System.Security.Cryptography.Pkcs.Asn1.OriginatorIdentifierOrKeyAsn.Decode(explicitReader, out decoded.Originator);
+            System.Security.Cryptography.Pkcs.Asn1.OriginatorIdentifierOrKeyAsn.Decode(ref explicitReader, rebind, out decoded.Originator);
             explicitReader.ThrowIfNotEmpty();
 
 
@@ -101,9 +98,9 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             {
                 explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
 
-                if (explicitReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpUkm))
+                if (explicitReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
                 {
-                    decoded.Ukm = tmpUkm;
+                    decoded.Ukm = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 }
                 else
                 {
@@ -113,7 +110,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 explicitReader.ThrowIfNotEmpty();
             }
 
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.KeyEncryptionAlgorithm);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.KeyEncryptionAlgorithm);
 
             // Decode SEQUENCE OF for RecipientEncryptedKeys
             {
@@ -123,7 +120,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                 while (collectionReader.HasData)
                 {
-                    System.Security.Cryptography.Pkcs.Asn1.RecipientEncryptedKeyAsn.Decode(collectionReader, out tmpItem); 
+                    System.Security.Cryptography.Pkcs.Asn1.RecipientEncryptedKeyAsn.Decode(ref collectionReader, rebind, out tmpItem);
                     tmpList.Add(tmpItem);
                 }
 
index 1699b7b..94bffbf 100644 (file)
@@ -17,16 +17,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         internal System.Security.Cryptography.Pkcs.Asn1.RecipientIdentifierAsn Rid;
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn KeyEncryptionAlgorithm;
         internal ReadOnlyMemory<byte> EncryptedKey;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Version);
             Rid.Encode(writer);
             KeyEncryptionAlgorithm.Encode(writer);
@@ -38,44 +38,41 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static KeyTransRecipientInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out KeyTransRecipientInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out KeyTransRecipientInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out KeyTransRecipientInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out KeyTransRecipientInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out KeyTransRecipientInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out KeyTransRecipientInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (!sequenceReader.TryReadInt32(out decoded.Version))
             {
                 sequenceReader.ThrowIfNotEmpty();
             }
 
-            System.Security.Cryptography.Pkcs.Asn1.RecipientIdentifierAsn.Decode(sequenceReader, out decoded.Rid);
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.KeyEncryptionAlgorithm);
+            System.Security.Cryptography.Pkcs.Asn1.RecipientIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.Rid);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.KeyEncryptionAlgorithm);
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpEncryptedKey))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.EncryptedKey = tmpEncryptedKey;
+                decoded.EncryptedKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index a10d709..1907c3b 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm;
         internal ReadOnlyMemory<byte> HashedMessage;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             HashAlgorithm.Encode(writer);
             writer.WriteOctetString(HashedMessage.Span);
             writer.PopSequence(tag);
@@ -34,37 +34,34 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static MessageImprint Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out MessageImprint decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out MessageImprint decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out MessageImprint decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out MessageImprint decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out MessageImprint decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out MessageImprint decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.HashAlgorithm);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.HashAlgorithm);
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpHashedMessage))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.HashedMessage = tmpHashedMessage;
+                decoded.HashedMessage = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index fdddb58..8f4b39f 100644 (file)
@@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Asn1;
 
+#nullable enable
 namespace System.Security.Cryptography.Pkcs.Asn1
 {
     [StructLayout(LayoutKind.Sequential)]
@@ -23,14 +24,14 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
             Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
             {
-                if (usedTags.TryGetValue(tag, out string existing))
+                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(Asn1Tag.Sequence, "IssuerAndSerialNumber");
             ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "SubjectKeyIdentifier");
             ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 1), "OriginatorKey");
@@ -39,13 +40,13 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            bool wroteValue = false;
+
             if (IssuerAndSerialNumber.HasValue)
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 IssuerAndSerialNumber.Value.Encode(writer);
                 wroteValue = true;
             }
@@ -54,7 +55,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteOctetString(new Asn1Tag(TagClass.ContextSpecific, 0), SubjectKeyIdentifier.Value.Span);
                 wroteValue = true;
             }
@@ -63,7 +64,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 OriginatorKey.Value.Encode(writer, new Asn1Tag(TagClass.ContextSpecific, 1));
                 wroteValue = true;
             }
@@ -76,34 +77,34 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
         internal static OriginatorIdentifierOrKeyAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out OriginatorIdentifierOrKeyAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out OriginatorIdentifierOrKeyAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out OriginatorIdentifierOrKeyAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out OriginatorIdentifierOrKeyAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             if (tag.HasSameClassAndValue(Asn1Tag.Sequence))
             {
                 System.Security.Cryptography.Pkcs.Asn1.IssuerAndSerialNumberAsn tmpIssuerAndSerialNumber;
-                System.Security.Cryptography.Pkcs.Asn1.IssuerAndSerialNumberAsn.Decode(reader, out tmpIssuerAndSerialNumber);
+                System.Security.Cryptography.Pkcs.Asn1.IssuerAndSerialNumberAsn.Decode(ref reader, rebind, out tmpIssuerAndSerialNumber);
                 decoded.IssuerAndSerialNumber = tmpIssuerAndSerialNumber;
 
             }
             else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
 
-                if (reader.TryReadPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 0), out ReadOnlyMemory<byte> tmpSubjectKeyIdentifier))
+                if (reader.TryReadPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 0), out tmpSpan))
                 {
-                    decoded.SubjectKeyIdentifier = tmpSubjectKeyIdentifier;
+                    decoded.SubjectKeyIdentifier = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 }
                 else
                 {
@@ -114,7 +115,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
             {
                 System.Security.Cryptography.Pkcs.Asn1.OriginatorPublicKeyAsn tmpOriginatorKey;
-                System.Security.Cryptography.Pkcs.Asn1.OriginatorPublicKeyAsn.Decode(reader, new Asn1Tag(TagClass.ContextSpecific, 1), out tmpOriginatorKey);
+                System.Security.Cryptography.Pkcs.Asn1.OriginatorPublicKeyAsn.Decode(ref reader, new Asn1Tag(TagClass.ContextSpecific, 1), rebind, out tmpOriginatorKey);
                 decoded.OriginatorKey = tmpOriginatorKey;
 
             }
index 5cbb167..76af43c 100644 (file)
@@ -16,16 +16,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal System.Security.Cryptography.Pkcs.Asn1.CertificateChoiceAsn[] CertificateSet;
         internal ReadOnlyMemory<byte>[] RevocationInfoChoices;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
 
             if (CertificateSet != null)
             {
@@ -33,7 +33,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
                 for (int i = 0; i < CertificateSet.Length; i++)
                 {
-                    CertificateSet[i].Encode(writer); 
+                    CertificateSet[i].Encode(writer);
                 }
                 writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
 
@@ -46,7 +46,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
                 for (int i = 0; i < RevocationInfoChoices.Length; i++)
                 {
-                    writer.WriteEncodedValue(RevocationInfoChoices[i].Span); 
+                    writer.WriteEncodedValue(RevocationInfoChoices[i].Span);
                 }
                 writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
 
@@ -59,33 +59,30 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static OriginatorInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out OriginatorInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out OriginatorInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out OriginatorInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out OriginatorInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out OriginatorInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out OriginatorInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
@@ -98,7 +95,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Pkcs.Asn1.CertificateChoiceAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Pkcs.Asn1.CertificateChoiceAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
@@ -119,7 +116,8 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        tmpItem = collectionReader.ReadEncodedValue(); 
+                        tmpSpan = collectionReader.ReadEncodedValue();
+                        tmpItem = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                         tmpList.Add(tmpItem);
                     }
 
index bcf5b96..0448009 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn Algorithm;
         internal ReadOnlyMemory<byte> PublicKey;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             Algorithm.Encode(writer);
             writer.WriteBitString(PublicKey.Span);
             writer.PopSequence(tag);
@@ -34,37 +34,34 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static OriginatorPublicKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out OriginatorPublicKeyAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out OriginatorPublicKeyAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out OriginatorPublicKeyAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out OriginatorPublicKeyAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out OriginatorPublicKeyAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out OriginatorPublicKeyAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.Algorithm);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.Algorithm);
 
-            if (sequenceReader.TryReadPrimitiveBitStringValue(out _, out ReadOnlyMemory<byte> tmpPublicKey))
+            if (sequenceReader.TryReadPrimitiveBitStringValue(out _, out tmpSpan))
             {
-                decoded.PublicKey = tmpPublicKey;
+                decoded.PublicKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index bc8c707..b33506c 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal string KeyAttrId;
         internal ReadOnlyMemory<byte>? KeyAttr;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteObjectIdentifier(KeyAttrId);
 
             if (KeyAttr.HasValue)
@@ -39,37 +39,35 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static OtherKeyAttributeAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out OtherKeyAttributeAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out OtherKeyAttributeAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out OtherKeyAttributeAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out OtherKeyAttributeAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out OtherKeyAttributeAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out OtherKeyAttributeAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.KeyAttrId = sequenceReader.ReadObjectIdentifierAsString();
 
             if (sequenceReader.HasData)
             {
-                decoded.KeyAttr = sequenceReader.ReadEncodedValue();
+                tmpSpan = sequenceReader.ReadEncodedValue();
+                decoded.KeyAttr = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
 
 
index dfd5ed5..ff2b70e 100644 (file)
@@ -16,16 +16,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         internal int Status;
         internal ReadOnlyMemory<byte>? StatusString;
         internal System.Security.Cryptography.Pkcs.Asn1.PkiFailureInfo? FailInfo;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Status);
 
             if (StatusString.HasValue)
@@ -55,32 +55,29 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static PkiStatusInfo Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out PkiStatusInfo decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out PkiStatusInfo decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out PkiStatusInfo decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out PkiStatusInfo decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PkiStatusInfo decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out PkiStatusInfo decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (!sequenceReader.TryReadInt32(out decoded.Status))
             {
@@ -90,7 +87,8 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
             if (sequenceReader.HasData)
             {
-                decoded.StatusString = sequenceReader.ReadEncodedValue();
+                tmpSpan = sequenceReader.ReadEncodedValue();
+                decoded.StatusString = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
 
 
index 405aa98..b70e9ae 100644 (file)
@@ -16,16 +16,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal string PolicyIdentifier;
         internal System.Security.Cryptography.Pkcs.Asn1.PolicyQualifierInfo[] 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 != null)
@@ -34,7 +34,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 writer.PushSequence();
                 for (int i = 0; i < PolicyQualifiers.Length; i++)
                 {
-                    PolicyQualifiers[i].Encode(writer); 
+                    PolicyQualifiers[i].Encode(writer);
                 }
                 writer.PopSequence();
 
@@ -47,33 +47,27 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static PolicyInformation Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out PolicyInformation decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out PolicyInformation decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out PolicyInformation decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out PolicyInformation decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PolicyInformation decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out PolicyInformation decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader collectionReader;
+
             decoded.PolicyIdentifier = sequenceReader.ReadObjectIdentifierAsString();
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
@@ -87,7 +81,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Pkcs.Asn1.PolicyQualifierInfo.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Pkcs.Asn1.PolicyQualifierInfo.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index e0aec7d..a1cfc84 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal string PolicyQualifierId;
         internal ReadOnlyMemory<byte> Qualifier;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteObjectIdentifier(PolicyQualifierId);
             writer.WriteEncodedValue(Qualifier.Span);
             writer.PopSequence(tag);
@@ -34,34 +34,32 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static PolicyQualifierInfo Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out PolicyQualifierInfo decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out PolicyQualifierInfo decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out PolicyQualifierInfo decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out PolicyQualifierInfo decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PolicyQualifierInfo decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out PolicyQualifierInfo decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.PolicyQualifierId = sequenceReader.ReadObjectIdentifierAsString();
-            decoded.Qualifier = sequenceReader.ReadEncodedValue();
+            tmpSpan = sequenceReader.ReadEncodedValue();
+            decoded.Qualifier = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
 
             sequenceReader.ThrowIfNotEmpty();
         }
index 174ab16..a68a568 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal System.Security.Cryptography.Pkcs.Asn1.KeyAgreeRecipientIdentifierAsn Rid;
         internal ReadOnlyMemory<byte> EncryptedKey;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             Rid.Encode(writer);
             writer.WriteOctetString(EncryptedKey.Span);
             writer.PopSequence(tag);
@@ -34,37 +34,34 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static RecipientEncryptedKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out RecipientEncryptedKeyAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out RecipientEncryptedKeyAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out RecipientEncryptedKeyAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out RecipientEncryptedKeyAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out RecipientEncryptedKeyAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out RecipientEncryptedKeyAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
-            System.Security.Cryptography.Pkcs.Asn1.KeyAgreeRecipientIdentifierAsn.Decode(sequenceReader, out decoded.Rid);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
+            System.Security.Cryptography.Pkcs.Asn1.KeyAgreeRecipientIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.Rid);
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpEncryptedKey))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.EncryptedKey = tmpEncryptedKey;
+                decoded.EncryptedKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index 7206aad..f00d35c 100644 (file)
@@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Asn1;
 
+#nullable enable
 namespace System.Security.Cryptography.Pkcs.Asn1
 {
     [StructLayout(LayoutKind.Sequential)]
@@ -22,14 +23,14 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
             Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
             {
-                if (usedTags.TryGetValue(tag, out string existing))
+                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(Asn1Tag.Sequence, "IssuerAndSerialNumber");
             ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "SubjectKeyIdentifier");
         }
@@ -37,13 +38,13 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            bool wroteValue = false;
+
             if (IssuerAndSerialNumber.HasValue)
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 IssuerAndSerialNumber.Value.Encode(writer);
                 wroteValue = true;
             }
@@ -52,7 +53,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteOctetString(new Asn1Tag(TagClass.ContextSpecific, 0), SubjectKeyIdentifier.Value.Span);
                 wroteValue = true;
             }
@@ -65,34 +66,34 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
         internal static RecipientIdentifierAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out RecipientIdentifierAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out RecipientIdentifierAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out RecipientIdentifierAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out RecipientIdentifierAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             if (tag.HasSameClassAndValue(Asn1Tag.Sequence))
             {
                 System.Security.Cryptography.Pkcs.Asn1.IssuerAndSerialNumberAsn tmpIssuerAndSerialNumber;
-                System.Security.Cryptography.Pkcs.Asn1.IssuerAndSerialNumberAsn.Decode(reader, out tmpIssuerAndSerialNumber);
+                System.Security.Cryptography.Pkcs.Asn1.IssuerAndSerialNumberAsn.Decode(ref reader, rebind, out tmpIssuerAndSerialNumber);
                 decoded.IssuerAndSerialNumber = tmpIssuerAndSerialNumber;
 
             }
             else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
 
-                if (reader.TryReadPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 0), out ReadOnlyMemory<byte> tmpSubjectKeyIdentifier))
+                if (reader.TryReadPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 0), out tmpSpan))
                 {
-                    decoded.SubjectKeyIdentifier = tmpSubjectKeyIdentifier;
+                    decoded.SubjectKeyIdentifier = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 }
                 else
                 {
index 510a241..f2d365d 100644 (file)
@@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Asn1;
 
+#nullable enable
 namespace System.Security.Cryptography.Pkcs.Asn1
 {
     [StructLayout(LayoutKind.Sequential)]
@@ -22,14 +23,14 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
             Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
             {
-                if (usedTags.TryGetValue(tag, out string existing))
+                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(Asn1Tag.Sequence, "Ktri");
             ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 1), "Kari");
         }
@@ -37,13 +38,13 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            bool wroteValue = false;
+
             if (Ktri.HasValue)
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 Ktri.Value.Encode(writer);
                 wroteValue = true;
             }
@@ -52,7 +53,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 Kari.Value.Encode(writer, new Asn1Tag(TagClass.ContextSpecific, 1));
                 wroteValue = true;
             }
@@ -65,32 +66,29 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
         internal static RecipientInfoAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out RecipientInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out RecipientInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out RecipientInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out RecipientInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            
+
             if (tag.HasSameClassAndValue(Asn1Tag.Sequence))
             {
                 System.Security.Cryptography.Pkcs.Asn1.KeyTransRecipientInfoAsn tmpKtri;
-                System.Security.Cryptography.Pkcs.Asn1.KeyTransRecipientInfoAsn.Decode(reader, out tmpKtri);
+                System.Security.Cryptography.Pkcs.Asn1.KeyTransRecipientInfoAsn.Decode(ref reader, rebind, out tmpKtri);
                 decoded.Ktri = tmpKtri;
 
             }
             else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
             {
                 System.Security.Cryptography.Pkcs.Asn1.KeyAgreeRecipientInfoAsn tmpKari;
-                System.Security.Cryptography.Pkcs.Asn1.KeyAgreeRecipientInfoAsn.Decode(reader, new Asn1Tag(TagClass.ContextSpecific, 1), out tmpKari);
+                System.Security.Cryptography.Pkcs.Asn1.KeyAgreeRecipientInfoAsn.Decode(ref reader, new Asn1Tag(TagClass.ContextSpecific, 1), rebind, out tmpKari);
                 decoded.Kari = tmpKari;
 
             }
index ac35084..b32bd30 100644 (file)
@@ -16,16 +16,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         internal ReadOnlyMemory<byte> SubjectKeyIdentifier;
         internal DateTimeOffset? Date;
         internal System.Security.Cryptography.Pkcs.Asn1.OtherKeyAttributeAsn? Other;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteOctetString(SubjectKeyIdentifier.Span);
 
             if (Date.HasValue)
@@ -46,36 +46,33 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static RecipientKeyIdentifier Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out RecipientKeyIdentifier decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out RecipientKeyIdentifier decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out RecipientKeyIdentifier decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out RecipientKeyIdentifier decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out RecipientKeyIdentifier decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out RecipientKeyIdentifier decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpSubjectKeyIdentifier))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.SubjectKeyIdentifier = tmpSubjectKeyIdentifier;
+                decoded.SubjectKeyIdentifier = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
@@ -92,7 +89,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
             {
                 System.Security.Cryptography.Pkcs.Asn1.OtherKeyAttributeAsn tmpOther;
-                System.Security.Cryptography.Pkcs.Asn1.OtherKeyAttributeAsn.Decode(sequenceReader, out tmpOther);
+                System.Security.Cryptography.Pkcs.Asn1.OtherKeyAttributeAsn.Decode(ref sequenceReader, rebind, out tmpOther);
                 decoded.Other = tmpOther;
 
             }
index 86febcf..10924f9 100644 (file)
@@ -16,16 +16,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         internal int? Seconds;
         internal int? Millis;
         internal int? Micros;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
 
             if (Seconds.HasValue)
             {
@@ -51,32 +51,26 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static Rfc3161Accuracy Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out Rfc3161Accuracy decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out Rfc3161Accuracy decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out Rfc3161Accuracy decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out Rfc3161Accuracy decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Rfc3161Accuracy decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out Rfc3161Accuracy decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
             {
index 11936f3..530d1f3 100644 (file)
@@ -15,35 +15,35 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     internal partial struct Rfc3161TimeStampReq
     {
         private static readonly byte[] s_defaultCertReq = { 0x01, 0x01, 0x00 };
-  
+
         internal int Version;
         internal System.Security.Cryptography.Pkcs.Asn1.MessageImprint MessageImprint;
         internal Oid ReqPolicy;
         internal ReadOnlyMemory<byte>? Nonce;
         internal bool CertReq;
         internal System.Security.Cryptography.Asn1.X509ExtensionAsn[] Extensions;
-      
+
 #if DEBUG
         static Rfc3161TimeStampReq()
         {
             Rfc3161TimeStampReq decoded = default;
-            AsnReader reader;
+            AsnValueReader reader;
 
-            reader = new AsnReader(s_defaultCertReq, AsnEncodingRules.DER);
+            reader = new AsnValueReader(s_defaultCertReq, AsnEncodingRules.DER);
             decoded.CertReq = 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.WriteInteger(Version);
             MessageImprint.Encode(writer);
 
@@ -58,7 +58,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 writer.WriteInteger(Nonce.Value.Span);
             }
 
-        
+
             // DEFAULT value handler for CertReq.
             {
                 using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
@@ -68,7 +68,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     if (!encoded.SequenceEqual(s_defaultCertReq))
                     {
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                     }
                 }
             }
@@ -80,7 +80,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                 for (int i = 0; i < Extensions.Length; i++)
                 {
-                    Extensions[i].Encode(writer); 
+                    Extensions[i].Encode(writer);
                 }
                 writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
 
@@ -93,41 +93,38 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static Rfc3161TimeStampReq Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out Rfc3161TimeStampReq decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out Rfc3161TimeStampReq decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out Rfc3161TimeStampReq decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out Rfc3161TimeStampReq decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Rfc3161TimeStampReq decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out Rfc3161TimeStampReq decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader defaultReader;
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader defaultReader;
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (!sequenceReader.TryReadInt32(out decoded.Version))
             {
                 sequenceReader.ThrowIfNotEmpty();
             }
 
-            System.Security.Cryptography.Pkcs.Asn1.MessageImprint.Decode(sequenceReader, out decoded.MessageImprint);
+            System.Security.Cryptography.Pkcs.Asn1.MessageImprint.Decode(ref sequenceReader, rebind, out decoded.MessageImprint);
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.ObjectIdentifier))
             {
@@ -137,7 +134,8 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
             {
-                decoded.Nonce = sequenceReader.ReadIntegerBytes();
+                tmpSpan = sequenceReader.ReadIntegerBytes();
+                decoded.Nonce = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
 
 
@@ -147,7 +145,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultCertReq, AsnEncodingRules.DER);
+                defaultReader = new AsnValueReader(s_defaultCertReq, AsnEncodingRules.DER);
                 decoded.CertReq = defaultReader.ReadBoolean();
             }
 
@@ -163,7 +161,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Asn1.X509ExtensionAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Asn1.X509ExtensionAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index 75c23a1..e7b85af 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal System.Security.Cryptography.Pkcs.Asn1.PkiStatusInfo Status;
         internal ReadOnlyMemory<byte>? TimeStampToken;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             Status.Encode(writer);
 
             if (TimeStampToken.HasValue)
@@ -39,37 +39,35 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static Rfc3161TimeStampResp Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out Rfc3161TimeStampResp decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out Rfc3161TimeStampResp decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out Rfc3161TimeStampResp decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out Rfc3161TimeStampResp decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Rfc3161TimeStampResp decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out Rfc3161TimeStampResp decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
-            System.Security.Cryptography.Pkcs.Asn1.PkiStatusInfo.Decode(sequenceReader, out decoded.Status);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
+            System.Security.Cryptography.Pkcs.Asn1.PkiStatusInfo.Decode(ref sequenceReader, rebind, out decoded.Status);
 
             if (sequenceReader.HasData)
             {
-                decoded.TimeStampToken = sequenceReader.ReadEncodedValue();
+                tmpSpan = sequenceReader.ReadEncodedValue();
+                decoded.TimeStampToken = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
 
 
index f75c739..ff0a95b 100644 (file)
@@ -15,7 +15,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     internal partial struct Rfc3161TstInfo
     {
         private static readonly byte[] s_defaultOrdering = { 0x01, 0x01, 0x00 };
-  
+
         internal int Version;
         internal Oid Policy;
         internal System.Security.Cryptography.Pkcs.Asn1.MessageImprint MessageImprint;
@@ -26,28 +26,28 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         internal ReadOnlyMemory<byte>? Nonce;
         internal System.Security.Cryptography.Asn1.GeneralNameAsn? Tsa;
         internal System.Security.Cryptography.Asn1.X509ExtensionAsn[] Extensions;
-      
+
 #if DEBUG
         static Rfc3161TstInfo()
         {
             Rfc3161TstInfo decoded = default;
-            AsnReader reader;
+            AsnValueReader reader;
 
-            reader = new AsnReader(s_defaultOrdering, AsnEncodingRules.DER);
+            reader = new AsnValueReader(s_defaultOrdering, AsnEncodingRules.DER);
             decoded.Ordering = 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.WriteInteger(Version);
             writer.WriteObjectIdentifier(Policy);
             MessageImprint.Encode(writer);
@@ -59,7 +59,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 Accuracy.Value.Encode(writer);
             }
 
-        
+
             // DEFAULT value handler for Ordering.
             {
                 using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
@@ -69,7 +69,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     if (!encoded.SequenceEqual(s_defaultOrdering))
                     {
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                     }
                 }
             }
@@ -95,7 +95,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
                 for (int i = 0; i < Extensions.Length; i++)
                 {
-                    Extensions[i].Encode(writer); 
+                    Extensions[i].Encode(writer);
                 }
                 writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
 
@@ -108,35 +108,32 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static Rfc3161TstInfo Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out Rfc3161TstInfo decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out Rfc3161TstInfo decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out Rfc3161TstInfo decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out Rfc3161TstInfo decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Rfc3161TstInfo decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out Rfc3161TstInfo decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            AsnReader defaultReader;
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            AsnValueReader defaultReader;
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (!sequenceReader.TryReadInt32(out decoded.Version))
             {
@@ -144,14 +141,15 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             }
 
             decoded.Policy = sequenceReader.ReadObjectIdentifier();
-            System.Security.Cryptography.Pkcs.Asn1.MessageImprint.Decode(sequenceReader, out decoded.MessageImprint);
-            decoded.SerialNumber = sequenceReader.ReadIntegerBytes();
+            System.Security.Cryptography.Pkcs.Asn1.MessageImprint.Decode(ref sequenceReader, rebind, out decoded.MessageImprint);
+            tmpSpan = sequenceReader.ReadIntegerBytes();
+            decoded.SerialNumber = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             decoded.GenTime = sequenceReader.ReadGeneralizedTime();
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence))
             {
                 System.Security.Cryptography.Pkcs.Asn1.Rfc3161Accuracy tmpAccuracy;
-                System.Security.Cryptography.Pkcs.Asn1.Rfc3161Accuracy.Decode(sequenceReader, out tmpAccuracy);
+                System.Security.Cryptography.Pkcs.Asn1.Rfc3161Accuracy.Decode(ref sequenceReader, rebind, out tmpAccuracy);
                 decoded.Accuracy = tmpAccuracy;
 
             }
@@ -163,14 +161,15 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultOrdering, AsnEncodingRules.DER);
+                defaultReader = new AsnValueReader(s_defaultOrdering, AsnEncodingRules.DER);
                 decoded.Ordering = defaultReader.ReadBoolean();
             }
 
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer))
             {
-                decoded.Nonce = sequenceReader.ReadIntegerBytes();
+                tmpSpan = sequenceReader.ReadIntegerBytes();
+                decoded.Nonce = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
 
 
@@ -178,7 +177,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             {
                 explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                 System.Security.Cryptography.Asn1.GeneralNameAsn tmpTsa;
-                System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(explicitReader, out tmpTsa);
+                System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(ref explicitReader, rebind, out tmpTsa);
                 decoded.Tsa = tmpTsa;
 
                 explicitReader.ThrowIfNotEmpty();
@@ -196,7 +195,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Asn1.X509ExtensionAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Asn1.X509ExtensionAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index 8589224..ca4374f 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal string SecretTypeId;
         internal ReadOnlyMemory<byte> SecretValue;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteObjectIdentifier(SecretTypeId);
             writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
             writer.WriteEncodedValue(SecretValue.Span);
@@ -36,37 +36,35 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static SecretBagAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out SecretBagAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out SecretBagAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out SecretBagAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out SecretBagAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SecretBagAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out SecretBagAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.SecretTypeId = sequenceReader.ReadObjectIdentifierAsString();
 
             explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
-            decoded.SecretValue = explicitReader.ReadEncodedValue();
+            tmpSpan = explicitReader.ReadEncodedValue();
+            decoded.SecretValue = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             explicitReader.ThrowIfNotEmpty();
 
 
index 43cf854..4feba0c 100644 (file)
@@ -9,6 +9,7 @@ using System.Runtime.InteropServices;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Asn1;
 
+#nullable enable
 namespace System.Security.Cryptography.Pkcs
 {
     [StructLayout(LayoutKind.Sequential)]
@@ -22,32 +23,32 @@ namespace System.Security.Cryptography.Pkcs
             var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
             Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
             {
-                if (usedTags.TryGetValue(tag, out string existing))
+                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), "SignedAttributes");
         }
 #endif
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            bool wroteValue = false;
+
             if (SignedAttributes != null)
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
 
                 writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
                 for (int i = 0; i < SignedAttributes.Length; i++)
                 {
-                    SignedAttributes[i].Encode(writer); 
+                    SignedAttributes[i].Encode(writer);
                 }
                 writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
 
@@ -62,22 +63,19 @@ namespace System.Security.Cryptography.Pkcs
 
         internal static SignedAttributesSet Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out SignedAttributesSet decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out SignedAttributesSet decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out SignedAttributesSet decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out SignedAttributesSet decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            AsnReader collectionReader;
-            
+            AsnValueReader collectionReader;
+
             if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
 
@@ -89,7 +87,7 @@ namespace System.Security.Cryptography.Pkcs
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index 32b96f8..75fa98e 100644 (file)
@@ -20,22 +20,22 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         internal System.Security.Cryptography.Pkcs.Asn1.CertificateChoiceAsn[] CertificateSet;
         internal ReadOnlyMemory<byte>[] Crls;
         internal System.Security.Cryptography.Pkcs.Asn1.SignerInfoAsn[] SignerInfos;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Version);
 
             writer.PushSetOf();
             for (int i = 0; i < DigestAlgorithms.Length; i++)
             {
-                DigestAlgorithms[i].Encode(writer); 
+                DigestAlgorithms[i].Encode(writer);
             }
             writer.PopSetOf();
 
@@ -47,7 +47,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
                 for (int i = 0; i < CertificateSet.Length; i++)
                 {
-                    CertificateSet[i].Encode(writer); 
+                    CertificateSet[i].Encode(writer);
                 }
                 writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
 
@@ -60,7 +60,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
                 for (int i = 0; i < Crls.Length; i++)
                 {
-                    writer.WriteEncodedValue(Crls[i].Span); 
+                    writer.WriteEncodedValue(Crls[i].Span);
                 }
                 writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
 
@@ -70,7 +70,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             writer.PushSetOf();
             for (int i = 0; i < SignerInfos.Length; i++)
             {
-                SignerInfos[i].Encode(writer); 
+                SignerInfos[i].Encode(writer);
             }
             writer.PopSetOf();
 
@@ -81,33 +81,30 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static SignedDataAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out SignedDataAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out SignedDataAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out SignedDataAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out SignedDataAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SignedDataAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out SignedDataAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (!sequenceReader.TryReadInt32(out decoded.Version))
             {
@@ -123,14 +120,14 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                 while (collectionReader.HasData)
                 {
-                    System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(collectionReader, out tmpItem); 
+                    System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref collectionReader, rebind, out tmpItem);
                     tmpList.Add(tmpItem);
                 }
 
                 decoded.DigestAlgorithms = tmpList.ToArray();
             }
 
-            System.Security.Cryptography.Pkcs.Asn1.EncapsulatedContentInfoAsn.Decode(sequenceReader, out decoded.EncapContentInfo);
+            System.Security.Cryptography.Pkcs.Asn1.EncapsulatedContentInfoAsn.Decode(ref sequenceReader, rebind, out decoded.EncapContentInfo);
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
@@ -143,7 +140,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Pkcs.Asn1.CertificateChoiceAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Pkcs.Asn1.CertificateChoiceAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
@@ -164,7 +161,8 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        tmpItem = collectionReader.ReadEncodedValue(); 
+                        tmpSpan = collectionReader.ReadEncodedValue();
+                        tmpItem = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                         tmpList.Add(tmpItem);
                     }
 
@@ -182,7 +180,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                 while (collectionReader.HasData)
                 {
-                    System.Security.Cryptography.Pkcs.Asn1.SignerInfoAsn.Decode(collectionReader, out tmpItem); 
+                    System.Security.Cryptography.Pkcs.Asn1.SignerInfoAsn.Decode(ref collectionReader, rebind, out tmpItem);
                     tmpList.Add(tmpItem);
                 }
 
index 9b7403b..276a55e 100644 (file)
@@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Asn1;
 
+#nullable enable
 namespace System.Security.Cryptography.Pkcs.Asn1
 {
     [StructLayout(LayoutKind.Sequential)]
@@ -22,14 +23,14 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
             Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
             {
-                if (usedTags.TryGetValue(tag, out string existing))
+                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(Asn1Tag.Sequence, "IssuerAndSerialNumber");
             ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "SubjectKeyIdentifier");
         }
@@ -37,13 +38,13 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            bool wroteValue = false;
+
             if (IssuerAndSerialNumber.HasValue)
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 IssuerAndSerialNumber.Value.Encode(writer);
                 wroteValue = true;
             }
@@ -52,7 +53,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteOctetString(new Asn1Tag(TagClass.ContextSpecific, 0), SubjectKeyIdentifier.Value.Span);
                 wroteValue = true;
             }
@@ -65,34 +66,34 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
         internal static SignerIdentifierAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out SignerIdentifierAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out SignerIdentifierAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out SignerIdentifierAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out SignerIdentifierAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             if (tag.HasSameClassAndValue(Asn1Tag.Sequence))
             {
                 System.Security.Cryptography.Pkcs.Asn1.IssuerAndSerialNumberAsn tmpIssuerAndSerialNumber;
-                System.Security.Cryptography.Pkcs.Asn1.IssuerAndSerialNumberAsn.Decode(reader, out tmpIssuerAndSerialNumber);
+                System.Security.Cryptography.Pkcs.Asn1.IssuerAndSerialNumberAsn.Decode(ref reader, rebind, out tmpIssuerAndSerialNumber);
                 decoded.IssuerAndSerialNumber = tmpIssuerAndSerialNumber;
 
             }
             else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
 
-                if (reader.TryReadPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 0), out ReadOnlyMemory<byte> tmpSubjectKeyIdentifier))
+                if (reader.TryReadPrimitiveOctetStringBytes(new Asn1Tag(TagClass.ContextSpecific, 0), out tmpSpan))
                 {
-                    decoded.SubjectKeyIdentifier = tmpSubjectKeyIdentifier;
+                    decoded.SubjectKeyIdentifier = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 }
                 else
                 {
index 5f43d4a..e381bbf 100644 (file)
@@ -21,16 +21,16 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn SignatureAlgorithm;
         internal ReadOnlyMemory<byte> SignatureValue;
         internal System.Security.Cryptography.Asn1.AttributeAsn[] UnsignedAttributes;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Version);
             Sid.Encode(writer);
             DigestAlgorithm.Encode(writer);
@@ -58,7 +58,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
                 for (int i = 0; i < UnsignedAttributes.Length; i++)
                 {
-                    UnsignedAttributes[i].Encode(writer); 
+                    UnsignedAttributes[i].Encode(writer);
                 }
                 writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
 
@@ -71,52 +71,50 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static SignerInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out SignerInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out SignerInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out SignerInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out SignerInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SignerInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out SignerInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (!sequenceReader.TryReadInt32(out decoded.Version))
             {
                 sequenceReader.ThrowIfNotEmpty();
             }
 
-            System.Security.Cryptography.Pkcs.Asn1.SignerIdentifierAsn.Decode(sequenceReader, out decoded.Sid);
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.DigestAlgorithm);
+            System.Security.Cryptography.Pkcs.Asn1.SignerIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.Sid);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.DigestAlgorithm);
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
-                decoded.SignedAttributes = sequenceReader.ReadEncodedValue();
+                tmpSpan = sequenceReader.ReadEncodedValue();
+                decoded.SignedAttributes = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
 
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.SignatureAlgorithm);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.SignatureAlgorithm);
 
-            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpSignatureValue))
+            if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
             {
-                decoded.SignatureValue = tmpSignatureValue;
+                decoded.SignatureValue = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
@@ -135,7 +133,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Asn1.AttributeAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index b3e7f57..ae7922f 100644 (file)
@@ -16,21 +16,21 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal System.Security.Cryptography.Pkcs.Asn1.EssCertId[] Certs;
         internal System.Security.Cryptography.Pkcs.Asn1.PolicyInformation[] Policies;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
 
             writer.PushSequence();
             for (int i = 0; i < Certs.Length; i++)
             {
-                Certs[i].Encode(writer); 
+                Certs[i].Encode(writer);
             }
             writer.PopSequence();
 
@@ -41,7 +41,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 writer.PushSequence();
                 for (int i = 0; i < Policies.Length; i++)
                 {
-                    Policies[i].Encode(writer); 
+                    Policies[i].Encode(writer);
                 }
                 writer.PopSequence();
 
@@ -54,33 +54,27 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static SigningCertificateAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out SigningCertificateAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out SigningCertificateAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out SigningCertificateAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out SigningCertificateAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SigningCertificateAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out SigningCertificateAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader collectionReader;
+
 
             // Decode SEQUENCE OF for Certs
             {
@@ -90,7 +84,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                 while (collectionReader.HasData)
                 {
-                    System.Security.Cryptography.Pkcs.Asn1.EssCertId.Decode(collectionReader, out tmpItem); 
+                    System.Security.Cryptography.Pkcs.Asn1.EssCertId.Decode(ref collectionReader, rebind, out tmpItem);
                     tmpList.Add(tmpItem);
                 }
 
@@ -109,7 +103,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Pkcs.Asn1.PolicyInformation.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Pkcs.Asn1.PolicyInformation.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index 76c24b1..01c8929 100644 (file)
@@ -16,21 +16,21 @@ namespace System.Security.Cryptography.Pkcs.Asn1
     {
         internal System.Security.Cryptography.Pkcs.Asn1.EssCertIdV2[] Certs;
         internal System.Security.Cryptography.Pkcs.Asn1.PolicyInformation[] Policies;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
 
             writer.PushSequence();
             for (int i = 0; i < Certs.Length; i++)
             {
-                Certs[i].Encode(writer); 
+                Certs[i].Encode(writer);
             }
             writer.PopSequence();
 
@@ -41,7 +41,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
                 writer.PushSequence();
                 for (int i = 0; i < Policies.Length; i++)
                 {
-                    Policies[i].Encode(writer); 
+                    Policies[i].Encode(writer);
                 }
                 writer.PopSequence();
 
@@ -54,33 +54,27 @@ namespace System.Security.Cryptography.Pkcs.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static SigningCertificateV2Asn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out SigningCertificateV2Asn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out SigningCertificateV2Asn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out SigningCertificateV2Asn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out SigningCertificateV2Asn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SigningCertificateV2Asn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out SigningCertificateV2Asn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader collectionReader;
+
 
             // Decode SEQUENCE OF for Certs
             {
@@ -90,7 +84,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                 while (collectionReader.HasData)
                 {
-                    System.Security.Cryptography.Pkcs.Asn1.EssCertIdV2.Decode(collectionReader, out tmpItem); 
+                    System.Security.Cryptography.Pkcs.Asn1.EssCertIdV2.Decode(ref collectionReader, rebind, out tmpItem);
                     tmpList.Add(tmpItem);
                 }
 
@@ -109,7 +103,7 @@ namespace System.Security.Cryptography.Pkcs.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Pkcs.Asn1.PolicyInformation.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Pkcs.Asn1.PolicyInformation.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index 0422a6f..82d07ca 100644 (file)
@@ -101,13 +101,13 @@ namespace System.Security.Cryptography.Pkcs
             }
 
             List<ContentInfoAsn> authSafeData = new List<ContentInfoAsn>();
-            AsnReader authSafeReader = new AsnReader(authSafeBytes, AsnEncodingRules.BER);
-            AsnReader sequenceReader = authSafeReader.ReadSequence();
+            AsnValueReader authSafeReader = new AsnValueReader(authSafeBytes.Span, AsnEncodingRules.BER);
+            AsnValueReader sequenceReader = authSafeReader.ReadSequence();
 
             authSafeReader.ThrowIfNotEmpty();
             while (sequenceReader.HasData)
             {
-                ContentInfoAsn.Decode(sequenceReader, out ContentInfoAsn contentInfo);
+                ContentInfoAsn.Decode(ref sequenceReader, authSafeBytes, out ContentInfoAsn contentInfo);
                 authSafeData.Add(contentInfo);
             }
 
index 3e8c8a6..4435318 100644 (file)
@@ -282,13 +282,13 @@ namespace System.Security.Cryptography.Pkcs
         private static List<Pkcs12SafeBag> ReadBags(ReadOnlyMemory<byte> serialized)
         {
             List<SafeBagAsn> serializedBags = new List<SafeBagAsn>();
-            AsnReader reader = new AsnReader(serialized, AsnEncodingRules.BER);
-            AsnReader sequenceReader = reader.ReadSequence();
+            AsnValueReader reader = new AsnValueReader(serialized.Span, AsnEncodingRules.BER);
+            AsnValueReader sequenceReader = reader.ReadSequence();
 
             reader.ThrowIfNotEmpty();
             while (sequenceReader.HasData)
             {
-                SafeBagAsn.Decode(sequenceReader, out SafeBagAsn serializedBag);
+                SafeBagAsn.Decode(ref sequenceReader, serialized, out SafeBagAsn serializedBag);
                 serializedBags.Add(serializedBag);
             }
 
index 9171c4f..48a9638 100644 (file)
@@ -67,15 +67,13 @@ namespace System.Security.Cryptography.Pkcs
             out int bytesRead,
             bool skipCopy = false)
         {
-            AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
-
-            if (!skipCopy)
-            {
-                reader = new AsnReader(reader.ReadEncodedValue().ToArray(), AsnEncodingRules.BER);
-            }
+            AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.BER);
+            // By using the default/empty ReadOnlyMemory value, the Decode method will have to
+            // make copies of the data when assigning ReadOnlyMemory fields.
+            ReadOnlyMemory<byte> rebind = skipCopy ? source : default;
 
             int localRead = reader.PeekEncodedValue().Length;
-            PrivateKeyInfoAsn.Decode(reader, out PrivateKeyInfoAsn privateKeyInfo);
+            PrivateKeyInfoAsn.Decode(ref reader, rebind, out PrivateKeyInfoAsn privateKeyInfo);
             bytesRead = localRead;
 
             return new Pkcs8PrivateKeyInfo(
index 05d4dd5..d53cf06 100644 (file)
@@ -85,10 +85,10 @@ namespace System.Security.Cryptography.Pkcs
 
             try
             {
-                AsnReader reader = new AsnReader(source, AsnEncodingRules.DER);
+                AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.DER);
                 int localBytesRead = reader.PeekEncodedValue().Length;
 
-                Rfc3161TimeStampResp.Decode(reader, out resp);
+                Rfc3161TimeStampResp.Decode(ref reader, source, out resp);
                 bytesConsumed = localBytesRead;
             }
             catch (CryptographicException) when (!shouldThrow)
@@ -346,10 +346,10 @@ namespace System.Security.Cryptography.Pkcs
                 // Since nothing says BER, assume DER only.
                 const AsnEncodingRules RuleSet = AsnEncodingRules.DER;
 
-                AsnReader reader = new AsnReader(encodedBytes, RuleSet);
-                ReadOnlyMemory<byte> firstElement = reader.PeekEncodedValue();
+                AsnValueReader reader = new AsnValueReader(encodedBytes.Span, RuleSet);
+                ReadOnlySpan<byte> firstElement = reader.PeekEncodedValue();
 
-                Rfc3161TimeStampReq.Decode(reader, out Rfc3161TimeStampReq req);
+                Rfc3161TimeStampReq.Decode(ref reader, encodedBytes, out Rfc3161TimeStampReq req);
 
                 request = new Rfc3161TimestampRequest
                 {
index d6c820b..0fca6f4 100644 (file)
@@ -297,11 +297,12 @@ namespace System.Security.Cryptography.Pkcs
 
             try
             {
-                AsnReader reader = new AsnReader(source, AsnEncodingRules.BER);
+                AsnValueReader reader = new AsnValueReader(source.Span, AsnEncodingRules.BER);
                 int bytesActuallyRead = reader.PeekEncodedValue().Length;
 
                 ContentInfoAsn.Decode(
-                    reader,
+                    ref reader,
+                    source,
                     out ContentInfoAsn contentInfo);
 
                 // https://tools.ietf.org/html/rfc3161#section-2.4.2
index 97f41e7..24ed0e5 100644 (file)
@@ -165,10 +165,13 @@ namespace System.Security.Cryptography.Pkcs
 
         internal void Decode(ReadOnlyMemory<byte> encodedMessage)
         {
+            AsnValueReader reader = new AsnValueReader(encodedMessage.Span, AsnEncodingRules.BER);
+
             // Windows (and thus NetFx) reads the leading data and ignores extra.
             // So use the Decode overload which doesn't throw on extra data.
             ContentInfoAsn.Decode(
-                new AsnReader(encodedMessage, AsnEncodingRules.BER),
+                ref reader,
+                encodedMessage,
                 out ContentInfoAsn contentInfo);
 
             if (contentInfo.ContentType != Oids.Pkcs7Signed)
index 811bf0d..2562c90 100644 (file)
@@ -275,13 +275,13 @@ namespace Internal.Cryptography.Pal
                 otherOid == null || otherOid == Oids.UserPrincipalName,
                 $"otherOid ({otherOid}) is not supported");
 
-            AsnReader reader = new AsnReader(extensionBytes, AsnEncodingRules.DER);
-            AsnReader sequenceReader = reader.ReadSequence();
+            AsnValueReader reader = new AsnValueReader(extensionBytes, AsnEncodingRules.DER);
+            AsnValueReader sequenceReader = reader.ReadSequence();
             reader.ThrowIfNotEmpty();
 
             while (sequenceReader.HasData)
             {
-                GeneralNameAsn.Decode(sequenceReader, out GeneralNameAsn generalName);
+                GeneralNameAsn.Decode(ref sequenceReader, extensionBytes, out GeneralNameAsn generalName);
 
                 switch (matchType)
                 {
index 039ed1d..e27a24b 100644 (file)
@@ -328,14 +328,14 @@ namespace Internal.Cryptography.Pal
 
         internal static ISet<string> ReadCertPolicyExtension(byte[] rawData)
         {
-            AsnReader reader = new AsnReader(rawData, AsnEncodingRules.DER);
-            AsnReader sequenceReader = reader.ReadSequence();
+            AsnValueReader reader = new AsnValueReader(rawData, AsnEncodingRules.DER);
+            AsnValueReader sequenceReader = reader.ReadSequence();
             reader.ThrowIfNotEmpty();
 
             HashSet<string> policies = new HashSet<string>();
             while (sequenceReader.HasData)
             {
-                PolicyInformationAsn.Decode(sequenceReader, out PolicyInformationAsn policyInformation);
+                PolicyInformationAsn.Decode(ref sequenceReader, rawData, out PolicyInformationAsn policyInformation);
                 policies.Add(policyInformation.PolicyIdentifier);
 
                 // There is an optional policy qualifier here, but it is for information
@@ -350,14 +350,14 @@ namespace Internal.Cryptography.Pal
 
         private static List<CertificatePolicyMappingAsn> ReadCertPolicyMappingsExtension(byte[] rawData)
         {
-            AsnReader reader = new AsnReader(rawData, AsnEncodingRules.DER);
-            AsnReader sequenceReader = reader.ReadSequence();
+            AsnValueReader reader = new AsnValueReader(rawData, AsnEncodingRules.DER);
+            AsnValueReader sequenceReader = reader.ReadSequence();
             reader.ThrowIfNotEmpty();
 
             List<CertificatePolicyMappingAsn> mappings = new List<CertificatePolicyMappingAsn>();
             while (sequenceReader.HasData)
             {
-                CertificatePolicyMappingAsn.Decode(sequenceReader, out CertificatePolicyMappingAsn mapping);
+                CertificatePolicyMappingAsn.Decode(ref sequenceReader, rawData, out CertificatePolicyMappingAsn mapping);
                 mappings.Add(mapping);
             }
 
index 26299bd..740c704 100644 (file)
@@ -244,13 +244,13 @@ namespace Internal.Cryptography.Pal
 
             try
             {
-                AsnReader reader = new AsnReader(crlDistributionPoints, AsnEncodingRules.DER);
-                AsnReader sequenceReader = reader.ReadSequence();
+                AsnValueReader reader = new AsnValueReader(crlDistributionPoints, AsnEncodingRules.DER);
+                AsnValueReader sequenceReader = reader.ReadSequence();
                 reader.ThrowIfNotEmpty();
 
                 while (sequenceReader.HasData)
                 {
-                    DistributionPointAsn.Decode(sequenceReader, out DistributionPointAsn distributionPoint);
+                    DistributionPointAsn.Decode(ref sequenceReader, crlDistributionPoints, out DistributionPointAsn distributionPoint);
 
                     // Only distributionPoint is supported
                     // Only fullName is supported, nameRelativeToCRLIssuer is for LDAP-based lookup.
index d9886c8..23ccd4d 100644 (file)
@@ -1111,13 +1111,13 @@ namespace Internal.Cryptography.Pal
         {
             try
             {
-                AsnReader reader = new AsnReader(authorityInformationAccess, AsnEncodingRules.DER);
-                AsnReader sequenceReader = reader.ReadSequence();
+                AsnValueReader reader = new AsnValueReader(authorityInformationAccess.Span, AsnEncodingRules.DER);
+                AsnValueReader sequenceReader = reader.ReadSequence();
                 reader.ThrowIfNotEmpty();
 
                 while (sequenceReader.HasData)
                 {
-                    AccessDescriptionAsn.Decode(sequenceReader, out AccessDescriptionAsn description);
+                    AccessDescriptionAsn.Decode(ref sequenceReader, authorityInformationAccess, out AccessDescriptionAsn description);
                     if (StringComparer.Ordinal.Equals(description.AccessMethod, recordTypeOid))
                     {
                         GeneralNameAsn name = description.AccessLocation;
index 1ef51eb..d929dea 100644 (file)
@@ -32,16 +32,16 @@ namespace Internal.Cryptography.Pal
         protected void ParsePkcs12(byte[] data)
         {
             // RFC7292 specifies BER instead of DER
-            AsnReader reader = new AsnReader(data, AsnEncodingRules.BER);
-            ReadOnlyMemory<byte> encodedData = reader.PeekEncodedValue();
+            AsnValueReader reader = new AsnValueReader(data, AsnEncodingRules.BER);
+            ReadOnlySpan<byte> encodedData = reader.PeekEncodedValue();
 
             // Windows compatibility: Ignore trailing data.
             if (encodedData.Length != data.Length)
             {
-                reader = new AsnReader(encodedData, AsnEncodingRules.BER);
+                reader = new AsnValueReader(encodedData, AsnEncodingRules.BER);
             }
 
-            PfxAsn.Decode(reader, out PfxAsn pfxAsn);
+            PfxAsn.Decode(ref reader, data, out PfxAsn pfxAsn);
 
             if (pfxAsn.AuthSafe.ContentType != Oids.Pkcs7Data)
             {
@@ -337,15 +337,15 @@ namespace Internal.Cryptography.Pal
             // and one plain (contains encrypted keys)
             ContentInfoAsn[] rented = ArrayPool<ContentInfoAsn>.Shared.Rent(10);
 
-            AsnReader outer = new AsnReader(authSafeContents, AsnEncodingRules.BER);
-            AsnReader reader = outer.ReadSequence();
+            AsnValueReader outer = new AsnValueReader(authSafeContents.Span, AsnEncodingRules.BER);
+            AsnValueReader reader = outer.ReadSequence();
             outer.ThrowIfNotEmpty();
             int i = 0;
 
             while (reader.HasData)
             {
                 GrowIfNeeded(ref rented, i);
-                ContentInfoAsn.Decode(reader, out rented[i]);
+                ContentInfoAsn.Decode(ref reader, authSafeContents, out rented[i]);
                 i++;
             }
 
@@ -668,13 +668,13 @@ namespace Internal.Cryptography.Pal
                 contentData = Helpers.DecodeOctetStringAsMemory(contentData);
             }
 
-            AsnReader outer = new AsnReader(contentData, AsnEncodingRules.BER);
-            AsnReader reader = outer.ReadSequence();
+            AsnValueReader outer = new AsnValueReader(contentData.Span, AsnEncodingRules.BER);
+            AsnValueReader reader = outer.ReadSequence();
             outer.ThrowIfNotEmpty();
 
             while (reader.HasData)
             {
-                SafeBagAsn.Decode(reader, out SafeBagAsn bag);
+                SafeBagAsn.Decode(ref reader, contentData, out SafeBagAsn bag);
 
                 if (bag.BagId == Oids.Pkcs12CertBag)
                 {
index a621083..f6ddd18 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
     {
         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);
@@ -34,34 +34,28 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         {
             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);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out AccessDescriptionAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out AccessDescriptionAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out AccessDescriptionAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out AccessDescriptionAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out AccessDescriptionAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+
             decoded.AccessMethod = sequenceReader.ReadObjectIdentifierAsString();
-            System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(sequenceReader, out decoded.AccessLocation);
+            System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(ref sequenceReader, rebind, out decoded.AccessLocation);
 
             sequenceReader.ThrowIfNotEmpty();
         }
index 7fa7bc7..abd2507 100644 (file)
@@ -14,32 +14,32 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
     internal partial struct BasicConstraintsAsn
     {
         private static readonly byte[] s_defaultCA = { 0x01, 0x01, 0x00 };
-  
+
         internal bool CA;
         internal int? PathLengthConstraint;
-      
+
 #if DEBUG
         static BasicConstraintsAsn()
         {
             BasicConstraintsAsn decoded = default;
-            AsnReader reader;
+            AsnValueReader reader;
 
-            reader = new AsnReader(s_defaultCA, AsnEncodingRules.DER);
+            reader = new AsnValueReader(s_defaultCA, AsnEncodingRules.DER);
             decoded.CA = reader.ReadBoolean();
             reader.ThrowIfNotEmpty();
         }
 #endif
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
-        
+
+
             // DEFAULT value handler for CA.
             {
                 using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
@@ -49,7 +49,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
 
                     if (!encoded.SequenceEqual(s_defaultCA))
                     {
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                     }
                 }
             }
@@ -67,33 +67,27 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static BasicConstraintsAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out BasicConstraintsAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out BasicConstraintsAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out BasicConstraintsAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out BasicConstraintsAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out BasicConstraintsAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out BasicConstraintsAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader defaultReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader defaultReader;
+
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Boolean))
             {
@@ -101,7 +95,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultCA, AsnEncodingRules.DER);
+                defaultReader = new AsnValueReader(s_defaultCA, AsnEncodingRules.DER);
                 decoded.CA = defaultReader.ReadBoolean();
             }
 
index 2617e69..a045b54 100644 (file)
@@ -16,16 +16,16 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         internal System.Security.Cryptography.X509Certificates.Asn1.TbsCertificateAsn TbsCertificate;
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn SignatureAlgorithm;
         internal ReadOnlyMemory<byte> SignatureValue;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             TbsCertificate.Encode(writer);
             SignatureAlgorithm.Encode(writer);
             writer.WriteBitString(SignatureValue.Span);
@@ -36,38 +36,35 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static CertificateAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out CertificateAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out CertificateAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out CertificateAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out CertificateAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CertificateAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out CertificateAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
-            System.Security.Cryptography.X509Certificates.Asn1.TbsCertificateAsn.Decode(sequenceReader, out decoded.TbsCertificate);
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.SignatureAlgorithm);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
+            System.Security.Cryptography.X509Certificates.Asn1.TbsCertificateAsn.Decode(ref sequenceReader, rebind, out decoded.TbsCertificate);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.SignatureAlgorithm);
 
-            if (sequenceReader.TryReadPrimitiveBitStringValue(out _, out ReadOnlyMemory<byte> tmpSignatureValue))
+            if (sequenceReader.TryReadPrimitiveBitStringValue(out _, out tmpSpan))
             {
-                decoded.SignatureValue = tmpSignatureValue;
+                decoded.SignatureValue = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index 0b6c32c..e21a9cd 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
     {
         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);
@@ -34,32 +34,26 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         {
             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);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out CertificatePolicyMappingAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out CertificatePolicyMappingAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out CertificatePolicyMappingAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CertificatePolicyMappingAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out CertificatePolicyMappingAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+
             decoded.IssuerDomainPolicy = sequenceReader.ReadObjectIdentifierAsString();
             decoded.SubjectDomainPolicy = sequenceReader.ReadObjectIdentifierAsString();
 
index eaa29c3..7325f62 100644 (file)
@@ -16,16 +16,16 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         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);
 
@@ -41,32 +41,26 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         {
             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);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out CertificateTemplateAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out CertificateTemplateAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out CertificateTemplateAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CertificateTemplateAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out CertificateTemplateAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+
             decoded.TemplateID = sequenceReader.ReadObjectIdentifierAsString();
 
             if (!sequenceReader.TryReadInt32(out decoded.TemplateMajorVersion))
index 3931f1f..a318835 100644 (file)
@@ -16,16 +16,16 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         internal System.Security.Cryptography.X509Certificates.Asn1.CertificationRequestInfoAsn CertificationRequestInfo;
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn SignatureAlgorithm;
         internal ReadOnlyMemory<byte> SignatureValue;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             CertificationRequestInfo.Encode(writer);
             SignatureAlgorithm.Encode(writer);
             writer.WriteBitString(SignatureValue.Span);
@@ -36,38 +36,35 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static CertificationRequestAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out CertificationRequestAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out CertificationRequestAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out CertificationRequestAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out CertificationRequestAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CertificationRequestAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out CertificationRequestAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
-            System.Security.Cryptography.X509Certificates.Asn1.CertificationRequestInfoAsn.Decode(sequenceReader, out decoded.CertificationRequestInfo);
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.SignatureAlgorithm);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
+            System.Security.Cryptography.X509Certificates.Asn1.CertificationRequestInfoAsn.Decode(ref sequenceReader, rebind, out decoded.CertificationRequestInfo);
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.SignatureAlgorithm);
 
-            if (sequenceReader.TryReadPrimitiveBitStringValue(out _, out ReadOnlyMemory<byte> tmpSignatureValue))
+            if (sequenceReader.TryReadPrimitiveBitStringValue(out _, out tmpSpan))
             {
-                decoded.SignatureValue = tmpSignatureValue;
+                decoded.SignatureValue = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index 1d88368..338bed0 100644 (file)
@@ -18,16 +18,16 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         internal ReadOnlyMemory<byte> Subject;
         internal System.Security.Cryptography.Asn1.SubjectPublicKeyInfoAsn SubjectPublicKeyInfo;
         internal System.Security.Cryptography.Asn1.AttributeAsn[] Attributes;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             writer.WriteInteger(Version);
             // Validator for tag constraint for Subject
             {
@@ -44,7 +44,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
             writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
             for (int i = 0; i < Attributes.Length; i++)
             {
-                Attributes[i].Encode(writer); 
+                Attributes[i].Encode(writer);
             }
             writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
 
@@ -55,41 +55,39 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static CertificationRequestInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out CertificationRequestInfoAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out CertificationRequestInfoAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out CertificationRequestInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out CertificationRequestInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CertificationRequestInfoAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out CertificationRequestInfoAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.Version = sequenceReader.ReadInteger();
             if (!sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16)))
             {
                 throw new CryptographicException();
             }
 
-            decoded.Subject = sequenceReader.ReadEncodedValue();
-            System.Security.Cryptography.Asn1.SubjectPublicKeyInfoAsn.Decode(sequenceReader, out decoded.SubjectPublicKeyInfo);
+            tmpSpan = sequenceReader.ReadEncodedValue();
+            decoded.Subject = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
+            System.Security.Cryptography.Asn1.SubjectPublicKeyInfoAsn.Decode(ref sequenceReader, rebind, out decoded.SubjectPublicKeyInfo);
 
             // Decode SEQUENCE OF for Attributes
             {
@@ -99,7 +97,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
 
                 while (collectionReader.HasData)
                 {
-                    System.Security.Cryptography.Asn1.AttributeAsn.Decode(collectionReader, out tmpItem); 
+                    System.Security.Cryptography.Asn1.AttributeAsn.Decode(ref collectionReader, rebind, out tmpItem);
                     tmpList.Add(tmpItem);
                 }
 
index a66cde6..94adda8 100644 (file)
@@ -17,16 +17,16 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         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)
             {
@@ -48,7 +48,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
                 writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
                 for (int i = 0; i < CRLIssuer.Length; i++)
                 {
-                    CRLIssuer[i].Encode(writer); 
+                    CRLIssuer[i].Encode(writer);
                 }
                 writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
 
@@ -61,40 +61,34 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         {
             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);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out DistributionPointAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out DistributionPointAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out DistributionPointAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out DistributionPointAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out DistributionPointAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            AsnValueReader 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);
+                System.Security.Cryptography.X509Certificates.Asn1.DistributionPointNameAsn.Decode(ref explicitReader, rebind, out tmpDistributionPoint);
                 decoded.DistributionPoint = tmpDistributionPoint;
 
                 explicitReader.ThrowIfNotEmpty();
@@ -118,7 +112,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index e64481a..99f26b5 100644 (file)
@@ -9,6 +9,7 @@ using System.Runtime.InteropServices;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Asn1;
 
+#nullable enable
 namespace System.Security.Cryptography.X509Certificates.Asn1
 {
     [StructLayout(LayoutKind.Sequential)]
@@ -23,14 +24,14 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
             var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
             Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
             {
-                if (usedTags.TryGetValue(tag, out string existing))
+                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");
         }
@@ -38,18 +39,18 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            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); 
+                    FullName[i].Encode(writer);
                 }
                 writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
 
@@ -60,7 +61,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 // Validator for tag constraint for NameRelativeToCRLIssuer
                 {
                     if (!Asn1Tag.TryDecode(NameRelativeToCRLIssuer.Value.Span, out Asn1Tag validateTag, out _) ||
@@ -82,22 +83,22 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
 
         internal static DistributionPointNameAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out DistributionPointNameAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out DistributionPointNameAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out DistributionPointNameAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out DistributionPointNameAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            AsnReader collectionReader;
-            
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
 
@@ -109,7 +110,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Asn1.GeneralNameAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
@@ -119,7 +120,8 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
             }
             else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
             {
-                decoded.NameRelativeToCRLIssuer = reader.ReadEncodedValue();
+                tmpSpan = reader.ReadEncodedValue();
+                decoded.NameRelativeToCRLIssuer = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
             else
             {
index 6b8d261..e9e3763 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
     {
         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)
             {
@@ -44,32 +44,26 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         {
             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);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out PolicyConstraintsAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out PolicyConstraintsAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out PolicyConstraintsAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PolicyConstraintsAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out PolicyConstraintsAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
index aead8bc..557f920 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
     {
         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)
@@ -39,37 +39,35 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         {
             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);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out PolicyInformationAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out PolicyInformationAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out PolicyInformationAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PolicyInformationAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out PolicyInformationAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
             decoded.PolicyIdentifier = sequenceReader.ReadObjectIdentifierAsString();
 
             if (sequenceReader.HasData)
             {
-                decoded.PolicyQualifiers = sequenceReader.ReadEncodedValue();
+                tmpSpan = sequenceReader.ReadEncodedValue();
+                decoded.PolicyQualifiers = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
             }
 
 
index 1847b67..241ba95 100644 (file)
@@ -15,7 +15,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
     internal partial struct TbsCertificateAsn
     {
         private static readonly byte[] s_defaultVersion = { 0x02, 0x01, 0x00 };
-  
+
         internal int Version;
         internal ReadOnlyMemory<byte> SerialNumber;
         internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn SignatureAlgorithm;
@@ -26,14 +26,14 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         internal ReadOnlyMemory<byte>? IssuerUniqueId;
         internal ReadOnlyMemory<byte>? SubjectUniqueId;
         internal System.Security.Cryptography.Asn1.X509ExtensionAsn[] Extensions;
-      
+
 #if DEBUG
         static TbsCertificateAsn()
         {
             TbsCertificateAsn decoded = default;
-            AsnReader reader;
+            AsnValueReader reader;
 
-            reader = new AsnReader(s_defaultVersion, AsnEncodingRules.DER);
+            reader = new AsnValueReader(s_defaultVersion, AsnEncodingRules.DER);
 
             if (!reader.TryReadInt32(out decoded.Version))
             {
@@ -43,16 +43,16 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
             reader.ThrowIfNotEmpty();
         }
 #endif
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
 
             // DEFAULT value handler for Version.
             {
@@ -64,7 +64,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
                     if (!encoded.SequenceEqual(s_defaultVersion))
                     {
                         writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
-                        writer.WriteEncodedValue(encoded.ToArray());
+                        writer.WriteEncodedValue(encoded);
                         writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
                     }
                 }
@@ -114,7 +114,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
                 writer.PushSequence();
                 for (int i = 0; i < Extensions.Length; i++)
                 {
-                    Extensions[i].Encode(writer); 
+                    Extensions[i].Encode(writer);
                 }
                 writer.PopSequence();
 
@@ -128,35 +128,32 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static TbsCertificateAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out TbsCertificateAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out TbsCertificateAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out TbsCertificateAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out TbsCertificateAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out TbsCertificateAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out TbsCertificateAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            AsnReader explicitReader;
-            AsnReader defaultReader;
-            AsnReader collectionReader;
-            
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+            AsnValueReader explicitReader;
+            AsnValueReader defaultReader;
+            AsnValueReader collectionReader;
+            ReadOnlySpan<byte> rebindSpan = rebind.Span;
+            int offset;
+            ReadOnlySpan<byte> tmpSpan;
+
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
             {
@@ -171,7 +168,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
             }
             else
             {
-                defaultReader = new AsnReader(s_defaultVersion, AsnEncodingRules.DER);
+                defaultReader = new AsnValueReader(s_defaultVersion, AsnEncodingRules.DER);
 
                 if (!defaultReader.TryReadInt32(out decoded.Version))
                 {
@@ -180,29 +177,32 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
 
             }
 
-            decoded.SerialNumber = sequenceReader.ReadIntegerBytes();
-            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.SignatureAlgorithm);
+            tmpSpan = sequenceReader.ReadIntegerBytes();
+            decoded.SerialNumber = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
+            System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.SignatureAlgorithm);
             if (!sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16)))
             {
                 throw new CryptographicException();
             }
 
-            decoded.Issuer = sequenceReader.ReadEncodedValue();
-            System.Security.Cryptography.X509Certificates.Asn1.ValidityAsn.Decode(sequenceReader, out decoded.Validity);
+            tmpSpan = sequenceReader.ReadEncodedValue();
+            decoded.Issuer = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
+            System.Security.Cryptography.X509Certificates.Asn1.ValidityAsn.Decode(ref sequenceReader, rebind, out decoded.Validity);
             if (!sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16)))
             {
                 throw new CryptographicException();
             }
 
-            decoded.Subject = sequenceReader.ReadEncodedValue();
-            System.Security.Cryptography.Asn1.SubjectPublicKeyInfoAsn.Decode(sequenceReader, out decoded.SubjectPublicKeyInfo);
+            tmpSpan = sequenceReader.ReadEncodedValue();
+            decoded.Subject = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
+            System.Security.Cryptography.Asn1.SubjectPublicKeyInfoAsn.Decode(ref sequenceReader, rebind, out decoded.SubjectPublicKeyInfo);
 
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
             {
 
-                if (sequenceReader.TryReadPrimitiveBitStringValue(new Asn1Tag(TagClass.ContextSpecific, 1), out _, out ReadOnlyMemory<byte> tmpIssuerUniqueId))
+                if (sequenceReader.TryReadPrimitiveBitStringValue(new Asn1Tag(TagClass.ContextSpecific, 1), out _, out tmpSpan))
                 {
-                    decoded.IssuerUniqueId = tmpIssuerUniqueId;
+                    decoded.IssuerUniqueId = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 }
                 else
                 {
@@ -215,9 +215,9 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
             if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2)))
             {
 
-                if (sequenceReader.TryReadPrimitiveBitStringValue(new Asn1Tag(TagClass.ContextSpecific, 2), out _, out ReadOnlyMemory<byte> tmpSubjectUniqueId))
+                if (sequenceReader.TryReadPrimitiveBitStringValue(new Asn1Tag(TagClass.ContextSpecific, 2), out _, out tmpSpan))
                 {
-                    decoded.SubjectUniqueId = tmpSubjectUniqueId;
+                    decoded.SubjectUniqueId = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
                 }
                 else
                 {
@@ -239,7 +239,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
 
                     while (collectionReader.HasData)
                     {
-                        System.Security.Cryptography.Asn1.X509ExtensionAsn.Decode(collectionReader, out tmpItem); 
+                        System.Security.Cryptography.Asn1.X509ExtensionAsn.Decode(ref collectionReader, rebind, out tmpItem);
                         tmpList.Add(tmpItem);
                     }
 
index 51ce321..b38ce1f 100644 (file)
@@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
 using System.Security.Cryptography;
 using System.Security.Cryptography.Asn1;
 
+#nullable enable
 namespace System.Security.Cryptography.X509Certificates.Asn1
 {
     [StructLayout(LayoutKind.Sequential)]
@@ -22,14 +23,14 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
             var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
             Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
             {
-                if (usedTags.TryGetValue(tag, out string existing))
+                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(Asn1Tag.UtcTime, "UtcTime");
             ensureUniqueTag(Asn1Tag.GeneralizedTime, "GeneralTime");
         }
@@ -37,13 +38,13 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
 
         internal void Encode(AsnWriter writer)
         {
-            bool wroteValue = false; 
-            
+            bool wroteValue = false;
+
             if (UtcTime.HasValue)
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteUtcTime(UtcTime.Value);
                 wroteValue = true;
             }
@@ -52,7 +53,7 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
             {
                 if (wroteValue)
                     throw new CryptographicException();
-                
+
                 writer.WriteGeneralizedTime(GeneralTime.Value, omitFractionalSeconds: true);
                 wroteValue = true;
             }
@@ -65,21 +66,18 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
 
         internal static TimeAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, out TimeAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, encoded, out TimeAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out TimeAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out TimeAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
             Asn1Tag tag = reader.PeekTag();
-            
+
             if (tag.HasSameClassAndValue(Asn1Tag.UtcTime))
             {
                 decoded.UtcTime = reader.ReadUtcTime();
index 06fec92..1a1af27 100644 (file)
@@ -15,16 +15,16 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
     {
         internal System.Security.Cryptography.X509Certificates.Asn1.TimeAsn NotBefore;
         internal System.Security.Cryptography.X509Certificates.Asn1.TimeAsn NotAfter;
-      
+
         internal void Encode(AsnWriter writer)
         {
             Encode(writer, Asn1Tag.Sequence);
         }
-    
+
         internal void Encode(AsnWriter writer, Asn1Tag tag)
         {
             writer.PushSequence(tag);
-            
+
             NotBefore.Encode(writer);
             NotAfter.Encode(writer);
             writer.PopSequence(tag);
@@ -34,34 +34,28 @@ namespace System.Security.Cryptography.X509Certificates.Asn1
         {
             return Decode(Asn1Tag.Sequence, encoded, ruleSet);
         }
-        
+
         internal static ValidityAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
         {
-            AsnReader reader = new AsnReader(encoded, ruleSet);
-            
-            Decode(reader, expectedTag, out ValidityAsn decoded);
+            AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
+
+            Decode(ref reader, expectedTag, encoded, out ValidityAsn decoded);
             reader.ThrowIfNotEmpty();
             return decoded;
         }
 
-        internal static void Decode(AsnReader reader, out ValidityAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out ValidityAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
-            Decode(reader, Asn1Tag.Sequence, out decoded);
+            Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
         }
 
-        internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out ValidityAsn decoded)
+        internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out ValidityAsn decoded)
         {
-            if (reader == null)
-                throw new ArgumentNullException(nameof(reader));
-
             decoded = default;
-            AsnReader sequenceReader = reader.ReadSequence(expectedTag);
-            
-            System.Security.Cryptography.X509Certificates.Asn1.TimeAsn.Decode(sequenceReader, out decoded.NotBefore);
-            System.Security.Cryptography.X509Certificates.Asn1.TimeAsn.Decode(sequenceReader, out decoded.NotAfter);
+            AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
+
+            System.Security.Cryptography.X509Certificates.Asn1.TimeAsn.Decode(ref sequenceReader, rebind, out decoded.NotBefore);
+            System.Security.Cryptography.X509Certificates.Asn1.TimeAsn.Decode(ref sequenceReader, rebind, out decoded.NotAfter);
 
             sequenceReader.ThrowIfNotEmpty();
         }