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.
{
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)
{
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();
}
{
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();
{
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
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);
}
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);
{
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
{
}
- 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
{
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
{
{
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);
{
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
{
usedTags.Add(tag, fieldName);
};
-
+
ensureUniqueTag(new Asn1Tag(UniversalTagNumber.T61String), "TeletexString");
ensureUniqueTag(new Asn1Tag(UniversalTagNumber.PrintableString), "PrintableString");
ensureUniqueTag(new Asn1Tag((UniversalTagNumber)28), "UniversalString");
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;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteCharacterString(UniversalTagNumber.PrintableString, PrintableString);
wroteValue = true;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
// Validator for tag constraint for UniversalString
{
if (!Asn1Tag.TryDecode(UniversalString.Value.Span, out Asn1Tag validateTag, out _) ||
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteCharacterString(UniversalTagNumber.UTF8String, Utf8String);
wroteValue = true;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteCharacterString(UniversalTagNumber.BMPString, BmpString);
wroteValue = true;
}
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);
}
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)))
{
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);
{
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();
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
+#nullable enable
namespace System.Security.Cryptography.Asn1
{
[StructLayout(LayoutKind.Sequential)]
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");
}
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;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteObjectIdentifier(Named);
wroteValue = true;
}
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;
}
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);
{
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))
{
}
- 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
{
{
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();
{
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
{
{
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)
{
{
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();
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();
{
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);
{
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
{
{
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);
{
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();
}
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");
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;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteCharacterString(new Asn1Tag(TagClass.ContextSpecific, 1), UniversalTagNumber.IA5String, Rfc822Name);
wroteValue = true;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteCharacterString(new Asn1Tag(TagClass.ContextSpecific, 2), UniversalTagNumber.IA5String, DnsName);
wroteValue = true;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
// Validator for tag constraint for X400Address
{
if (!Asn1Tag.TryDecode(X400Address.Value.Span, out Asn1Tag validateTag, out _) ||
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 4));
writer.WriteEncodedValue(DirectoryName.Value.Span);
writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 4));
{
if (wroteValue)
throw new CryptographicException();
-
+
EdiPartyName.Value.Encode(writer, new Asn1Tag(TagClass.ContextSpecific, 5));
wroteValue = true;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteCharacterString(new Asn1Tag(TagClass.ContextSpecific, 6), UniversalTagNumber.IA5String, Uri);
wroteValue = true;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteOctetString(new Asn1Tag(TagClass.ContextSpecific, 7), IPAddress.Value.Span);
wroteValue = true;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteObjectIdentifier(new Asn1Tag(TagClass.ContextSpecific, 8), RegisteredId);
wroteValue = true;
}
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;
}
}
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;
}
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
{
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.
{
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));
}
}
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));
}
}
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));
}
}
{
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);
}
{
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);
{
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();
{
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);
{
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
{
{
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);
{
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();
}
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);
writer.WriteInteger(KeyLength.Value);
}
-
+
// DEFAULT value handler for Prf.
{
using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
if (!encoded.SequenceEqual(s_defaultPrf))
{
- writer.WriteEncodedValue(encoded.ToArray());
+ writer.WriteEncodedValue(encoded);
}
}
}
{
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))
{
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);
}
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
+#nullable enable
namespace System.Security.Cryptography.Asn1
{
[StructLayout(LayoutKind.Sequential)]
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");
}
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;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
OtherSource.Value.Encode(writer);
wroteValue = true;
}
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
{
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;
}
{
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);
{
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();
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))
{
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))
if (!encoded.SequenceEqual(s_defaultIterationCount))
{
- writer.WriteEncodedValue(encoded.ToArray());
+ writer.WriteEncodedValue(encoded);
}
}
}
{
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
{
}
else
{
- defaultReader = new AsnReader(s_defaultIterationCount, AsnEncodingRules.DER);
+ defaultReader = new AsnValueReader(s_defaultIterationCount, AsnEncodingRules.DER);
if (!defaultReader.TryReadInt32(out decoded.IterationCount))
{
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);
{
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;
}
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);
writer.PushSetOf();
for (int i = 0; i < BagAttributes.Length; i++)
{
- BagAttributes[i].Encode(writer);
+ BagAttributes[i].Encode(writer);
}
writer.PopSetOf();
{
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();
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);
}
{
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);
{
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();
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);
{
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
{
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);
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));
{
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)))
{
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);
}
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);
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));
{
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
{
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);
}
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))
{
reader.ThrowIfNotEmpty();
- reader = new AsnReader(s_defaultTrailerField, AsnEncodingRules.DER);
+ reader = new AsnValueReader(s_defaultTrailerField, AsnEncodingRules.DER);
if (!reader.TryReadInt32(out decoded.TrailerField))
{
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.
{
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));
}
}
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));
}
}
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));
}
}
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));
}
}
{
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);
}
}
else
{
- defaultReader = new AsnReader(s_defaultSaltLength, AsnEncodingRules.DER);
+ defaultReader = new AsnValueReader(s_defaultSaltLength, AsnEncodingRules.DER);
if (!defaultReader.TryReadInt32(out decoded.SaltLength))
{
}
else
{
- defaultReader = new AsnReader(s_defaultTrailerField, AsnEncodingRules.DER);
+ defaultReader = new AsnValueReader(s_defaultTrailerField, AsnEncodingRules.DER);
if (!defaultReader.TryReadInt32(out decoded.TrailerField))
{
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);
{
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))
{
{
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);
{
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();
{
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);
{
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))
{
}
- 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
{
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);
{
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();
}
{
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);
{
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
{
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))
if (!encoded.SequenceEqual(s_defaultCritical))
{
- writer.WriteEncodedValue(encoded.ToArray());
+ writer.WriteEncodedValue(encoded);
}
}
}
{
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))
}
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
{
<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.
[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<byte> 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);
}
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
-
+
internal static <xsl:value-of select="@name" /> Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> 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<byte> 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<byte> 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 > 0">
+ ReadOnlySpan<byte> rebindSpan = rebind.Span;
+ int offset;
+ ReadOnlySpan<byte> tmpSpan;</xsl:if>
+<xsl:apply-templates mode="Decode" />
sequenceReader.ThrowIfNotEmpty();
}
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();
internal static <xsl:value-of select="@name" /> Decode(ReadOnlyMemory<byte> 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<byte> 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 > 0">
+ ReadOnlySpan<byte> rebindSpan = rebind.Span;
+ int offset;
+ ReadOnlySpan<byte> tmpSpan;</xsl:if>
+<xsl:apply-templates select="*" mode="Decode" />
else
{
throw new CryptographicException();
<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>
<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">
<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))
if (!encoded.SequenceEqual(<xsl:call-template name="DefaultValueField"/>))
{
- writer.WriteEncodedValue(encoded.ToArray());
+ writer.WriteEncodedValue(encoded);
}
}
}
</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">
{
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>
{
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>
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" />);
}
}
</xsl:otherwise>
</xsl:choose>
</xsl:template>
-
+
<xsl:template match="*" mode="Decode" xml:space="default">
<xsl:choose>
<xsl:when test="parent::asn:Choice">
<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" />
<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">
<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>
<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" />
<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<byte><xsl:if test="@optional | parent::asn:Choice">?</xsl:if> <xsl:value-of select="@name" />;</xsl:template>
<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">
<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<byte> 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"/>{
<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<byte> 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"/>{
<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" />
<xsl:if test="1" xml:space="preserve">
<xsl:value-of select="$indent"/><xsl:value-of select="$name"/> = <xsl:value-of select="$readerName"/>.ReadEnumeratedValue<<xsl:value-of select="@backingType"/>>(<xsl:call-template name="MaybeImplicitCall0"/>);</xsl:if>
</xsl:template>
-
+
<xsl:template match="asn:Enumerated" mode="DefaultTag">Asn1Tag.Enumerated</xsl:template>
<!-- All character string types -->
<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" />
<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">
<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 < <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" />
<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"/> }
<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" />
<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" />
<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" />
<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) -->
<!-- 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">
#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>
/// 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">
/// "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>
public bool TryReadPrimitiveBitStringValue(
Asn1Tag expectedTag,
out int unusedBitCount,
- out ReadOnlyMemory<byte> value)
+ out ReadOnlySpan<byte> value)
{
bool isPrimitive = TryReadPrimitiveBitStringValue(
expectedTag,
{
// 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;
}
/// 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,
/// <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,
out int? contentsLength,
out int headerLength,
out unusedBitCount,
- out ReadOnlyMemory<byte> value,
+ out ReadOnlySpan<byte> value,
out byte normalizedLastByte))
{
if (value.Length > destination.Length)
}
/// <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>
/// 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)
{
/// <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
}
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
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)
}
Debug.Assert(unusedBitCount == 0);
- value = ReadOnlyMemory<byte>.Empty;
+ value = ReadOnlySpan<byte>.Empty;
normalizedLastByte = 0;
return;
}
// 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)
}
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)
{
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;
}
private void CopyConstructedBitString(
- ReadOnlyMemory<byte> source,
+ ReadOnlySpan<byte> source,
Span<byte> destination,
bool isIndefinite,
out int unusedBitCount,
}
private int ProcessConstructedBitString(
- ReadOnlyMemory<byte> source,
+ ReadOnlySpan<byte> source,
Span<byte> destination,
BitStringCopyAction? copyAction,
bool isIndefinite,
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)
{
}
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;
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
{
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);
}
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,
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);
}
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,
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;
+ }
+ }
}
#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.
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);
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;
+ }
+ }
}
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.
/// 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>
/// 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);
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;
+ }
+ }
}
#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.
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,
}
}
}
+
+ 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;
+ }
+ }
}
#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.
/// 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>
/// <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);
/// </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
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);
return false;
}
- private ReadOnlyMemory<byte> GetIntegerContents(
+ private ReadOnlySpan<byte> GetIntegerContents(
Asn1Tag expectedTag,
UniversalTagNumber tagNumber,
out int headerLength)
}
// 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);
return contents;
}
- private bool TryReadSignedInteger(
+ internal bool TryReadSignedInteger(
int sizeLimit,
Asn1Tag expectedTag,
UniversalTagNumber tagNumber,
{
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)
{
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);
return true;
}
- private bool TryReadUnsignedInteger(
+ internal bool TryReadUnsignedInteger(
int sizeLimit,
Asn1Tag expectedTag,
UniversalTagNumber tagNumber,
{
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)
{
}
// 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;
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);
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;
+ }
+ }
}
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
}
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.
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 << (0),
+ /// NonRepudiation = 1 << (1),
+ /// KeyEncipherment = 1 << (2),
+ /// DataEncipherment = 1 << (3),
+ /// KeyAgreement = 1 << (4),
+ /// KeyCertSign = 1 << (5),
+ /// CrlSign = 1 << (6),
+ /// EncipherOnly = 1 << (7),
+ /// DecipherOnly = 1 << (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;
+ }
+ }
}
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.
_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);
+ }
+ }
}
#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
/// 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,
/// <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,
out Asn1Tag actualTag,
out int? contentLength,
out int headerLength,
- out ReadOnlyMemory<byte> contents))
+ out ReadOnlySpan<byte> contents))
{
if (contents.Length > destination.Length)
{
return false;
}
- contents.Span.CopyTo(destination);
+ contents.CopyTo(destination);
bytesWritten = contents.Length;
_data = _data.Slice(headerLength + contents.Length);
return true;
}
/// <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>
/// 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()
/// <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
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);
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)
{
return true;
}
- private bool TryReadPrimitiveOctetStringBytes(
+ internal bool TryReadPrimitiveOctetStringBytes(
Asn1Tag expectedTag,
UniversalTagNumber universalTagNumber,
- out ReadOnlyMemory<byte> contents)
+ out ReadOnlySpan<byte> contents)
{
if (TryReadPrimitiveOctetStringBytes(
expectedTag,
/// <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>
/// 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>
/// 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,
}
private void CopyConstructedOctetString(
- ReadOnlyMemory<byte> source,
+ ReadOnlySpan<byte> source,
Span<byte> destination,
bool isIndefinite,
out int bytesRead,
}
private int CopyConstructedOctetString(
- ReadOnlyMemory<byte> source,
+ ReadOnlySpan<byte> source,
Span<byte> destination,
bool write,
bool isIndefinite,
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)
{
// 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);
if (write)
{
- contents.Span.CopyTo(curDest);
+ contents.CopyTo(curDest);
curDest = curDest.Slice(contents.Length);
}
}
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
{
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);
}
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,
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);
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;
+ }
+ }
}
#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
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.
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;
+ }
+ }
}
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>
/// 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>
/// <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);
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;
}
}
}
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">
/// 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>
/// 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>
/// 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>
/// <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);
suffix = EndOfContentsEncodedLength;
}
- ReadOnlyMemory<byte> contents = Slice(_data, headerLength, length.Value);
+ ReadOnlySpan<byte> contents = Slice(_data, headerLength, length.Value);
if (!skipSortOrderValidation)
{
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);
}
}
_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;
}
}
}
#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>
/// <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),
/// <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>
public bool TryReadPrimitiveCharacterStringBytes(
Asn1Tag expectedTag,
UniversalTagNumber encodingType,
- out ReadOnlyMemory<byte> contents)
+ out ReadOnlySpan<byte> contents)
{
CheckCharacterStringEncodingType(encodingType);
/// 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(
/// <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(
/// 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(
/// <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(
/// 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(
/// <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(
/// <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">
/// 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)"/>
/// <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)
out Asn1Tag actualTag,
out int? contentLength,
out int headerLength,
- out ReadOnlyMemory<byte> contents,
+ out ReadOnlySpan<byte> contents,
universalTagNumber))
{
bytesWritten = contents.Length;
return false;
}
- contents.Span.CopyTo(destination);
+ contents.CopyTo(destination);
bytesRead = headerLength + bytesWritten;
return true;
}
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;
+ }
+ }
}
#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>
public DateTimeOffset ReadUtcTime(int twoDigitYearMax = 2049) =>
ReadUtcTime(Asn1Tag.UtcTime, twoDigitYearMax);
-
/// <summary>
/// Reads the next value as a UTCTime with a specified tag.
/// </summary>
// 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,
}
}
}
+
+ 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;
+ }
+ }
}
/// <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.
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>
/// <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);
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>.
/// </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;
}
}
/// <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;
}
length = null;
bytesRead = 0;
- CheckEncodingRules(ruleSet);
+ AssertEncodingRules(ruleSet);
if (source.IsEmpty)
{
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;
/// 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.
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);
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 &&
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);
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 &&
}
}
- 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)
{
}
}
}
+
+ /// <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);
+ }
+ }
}
{
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)
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)
{
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)
{
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)
{
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)
{
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.
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.
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)
{
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();
+ });
+ }
}
}
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]
{
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)
{
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)
}
}
- 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++;
}
{
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();
{
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
{
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();
}
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
+#nullable enable
namespace System.Security.Cryptography.Pkcs.Asn1
{
[StructLayout(LayoutKind.Sequential)]
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 _) ||
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
{
{
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)
{
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();
}
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)
writer.PushSetOf();
for (int i = 0; i < RecipientInfos.Length; i++)
{
- RecipientInfos[i].Encode(writer);
+ RecipientInfos[i].Encode(writer);
}
writer.PopSetOf();
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));
{
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))
{
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;
}
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)))
{
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);
}
{
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)
{
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
{
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;
}
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))
if (!encoded.SequenceEqual(s_defaultHashAlgorithm))
{
- writer.WriteEncodedValue(encoded.ToArray());
+ writer.WriteEncodedValue(encoded);
}
}
}
{
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
{
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;
}
{
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 _) ||
{
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();
}
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
+#nullable enable
namespace System.Security.Cryptography.Pkcs.Asn1
{
[StructLayout(LayoutKind.Sequential)]
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");
}
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;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
RKeyId.Value.Encode(writer, new Asn1Tag(TagClass.ContextSpecific, 0));
wroteValue = true;
}
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;
}
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);
writer.PushSequence();
for (int i = 0; i < RecipientEncryptedKeys.Length; i++)
{
- RecipientEncryptedKeys[i].Encode(writer);
+ RecipientEncryptedKeys[i].Encode(writer);
}
writer.PopSequence();
{
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))
{
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();
{
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
{
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
{
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);
}
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);
{
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
{
{
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);
{
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
{
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
+#nullable enable
namespace System.Security.Cryptography.Pkcs.Asn1
{
[StructLayout(LayoutKind.Sequential)]
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");
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;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteOctetString(new Asn1Tag(TagClass.ContextSpecific, 0), SubjectKeyIdentifier.Value.Span);
wroteValue = true;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
OriginatorKey.Value.Encode(writer, new Asn1Tag(TagClass.ContextSpecific, 1));
wroteValue = true;
}
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
{
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;
}
{
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)
{
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));
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));
{
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)))
{
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);
}
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);
}
{
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);
{
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
{
{
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)
{
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();
}
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)
{
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))
{
if (sequenceReader.HasData)
{
- decoded.StatusString = sequenceReader.ReadEncodedValue();
+ tmpSpan = sequenceReader.ReadEncodedValue();
+ decoded.StatusString = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
}
{
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)
writer.PushSequence();
for (int i = 0; i < PolicyQualifiers.Length; i++)
{
- PolicyQualifiers[i].Encode(writer);
+ PolicyQualifiers[i].Encode(writer);
}
writer.PopSequence();
{
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))
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);
}
{
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);
{
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();
}
{
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);
{
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
{
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
+#nullable enable
namespace System.Security.Cryptography.Pkcs.Asn1
{
[StructLayout(LayoutKind.Sequential)]
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");
}
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;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteOctetString(new Asn1Tag(TagClass.ContextSpecific, 0), SubjectKeyIdentifier.Value.Span);
wroteValue = true;
}
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
{
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
+#nullable enable
namespace System.Security.Cryptography.Pkcs.Asn1
{
[StructLayout(LayoutKind.Sequential)]
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");
}
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;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
Kari.Value.Encode(writer, new Asn1Tag(TagClass.ContextSpecific, 1));
wroteValue = true;
}
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;
}
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)
{
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
{
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;
}
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)
{
{
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))
{
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);
writer.WriteInteger(Nonce.Value.Span);
}
-
+
// DEFAULT value handler for CertReq.
{
using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
if (!encoded.SequenceEqual(s_defaultCertReq))
{
- writer.WriteEncodedValue(encoded.ToArray());
+ writer.WriteEncodedValue(encoded);
}
}
}
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));
{
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))
{
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();
}
}
else
{
- defaultReader = new AsnReader(s_defaultCertReq, AsnEncodingRules.DER);
+ defaultReader = new AsnValueReader(s_defaultCertReq, AsnEncodingRules.DER);
decoded.CertReq = defaultReader.ReadBoolean();
}
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);
}
{
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)
{
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();
}
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;
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);
Accuracy.Value.Encode(writer);
}
-
+
// DEFAULT value handler for Ordering.
{
using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
if (!encoded.SequenceEqual(s_defaultOrdering))
{
- writer.WriteEncodedValue(encoded.ToArray());
+ writer.WriteEncodedValue(encoded);
}
}
}
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));
{
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))
{
}
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;
}
}
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();
}
{
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();
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);
}
{
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);
{
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();
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
+#nullable enable
namespace System.Security.Cryptography.Pkcs
{
[StructLayout(LayoutKind.Sequential)]
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));
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)))
{
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);
}
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();
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));
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));
writer.PushSetOf();
for (int i = 0; i < SignerInfos.Length; i++)
{
- SignerInfos[i].Encode(writer);
+ SignerInfos[i].Encode(writer);
}
writer.PopSetOf();
{
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))
{
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)))
{
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);
}
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);
}
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);
}
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
+#nullable enable
namespace System.Security.Cryptography.Pkcs.Asn1
{
[StructLayout(LayoutKind.Sequential)]
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");
}
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;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteOctetString(new Asn1Tag(TagClass.ContextSpecific, 0), SubjectKeyIdentifier.Value.Span);
wroteValue = true;
}
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
{
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);
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));
{
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
{
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);
}
{
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();
writer.PushSequence();
for (int i = 0; i < Policies.Length; i++)
{
- Policies[i].Encode(writer);
+ Policies[i].Encode(writer);
}
writer.PopSequence();
{
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
{
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);
}
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);
}
{
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();
writer.PushSequence();
for (int i = 0; i < Policies.Length; i++)
{
- Policies[i].Encode(writer);
+ Policies[i].Encode(writer);
}
writer.PopSequence();
{
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
{
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);
}
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);
}
}
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);
}
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);
}
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(
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)
// 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
{
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
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)
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)
{
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
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);
}
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.
{
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;
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)
{
// 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++;
}
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)
{
{
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);
{
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();
}
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))
if (!encoded.SequenceEqual(s_defaultCA))
{
- writer.WriteEncodedValue(encoded.ToArray());
+ writer.WriteEncodedValue(encoded);
}
}
}
{
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))
{
}
else
{
- defaultReader = new AsnReader(s_defaultCA, AsnEncodingRules.DER);
+ defaultReader = new AsnValueReader(s_defaultCA, AsnEncodingRules.DER);
decoded.CA = defaultReader.ReadBoolean();
}
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);
{
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
{
{
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);
{
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();
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);
{
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))
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);
{
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
{
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
{
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));
{
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
{
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);
}
internal System.Security.Cryptography.X509Certificates.Asn1.DistributionPointNameAsn? DistributionPoint;
internal System.Security.Cryptography.X509Certificates.Asn1.ReasonFlagsAsn? Reasons;
internal System.Security.Cryptography.Asn1.GeneralNameAsn[] CRLIssuer;
-
+
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
-
+
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
-
+
if (DistributionPoint.HasValue)
{
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
for (int i = 0; i < CRLIssuer.Length; i++)
{
- CRLIssuer[i].Encode(writer);
+ CRLIssuer[i].Encode(writer);
}
writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
{
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();
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);
}
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
+#nullable enable
namespace System.Security.Cryptography.X509Certificates.Asn1
{
[StructLayout(LayoutKind.Sequential)]
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");
}
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));
{
if (wroteValue)
throw new CryptographicException();
-
+
// Validator for tag constraint for NameRelativeToCRLIssuer
{
if (!Asn1Tag.TryDecode(NameRelativeToCRLIssuer.Value.Span, out Asn1Tag validateTag, out _) ||
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)))
{
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);
}
}
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
{
{
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)
{
{
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)))
{
{
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)
{
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();
}
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;
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))
{
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.
{
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));
}
}
writer.PushSequence();
for (int i = 0; i < Extensions.Length; i++)
{
- Extensions[i].Encode(writer);
+ Extensions[i].Encode(writer);
}
writer.PopSequence();
{
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)))
{
}
else
{
- defaultReader = new AsnReader(s_defaultVersion, AsnEncodingRules.DER);
+ defaultReader = new AsnValueReader(s_defaultVersion, AsnEncodingRules.DER);
if (!defaultReader.TryReadInt32(out decoded.Version))
{
}
- 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
{
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
{
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);
}
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
+#nullable enable
namespace System.Security.Cryptography.X509Certificates.Asn1
{
[StructLayout(LayoutKind.Sequential)]
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");
}
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;
}
{
if (wroteValue)
throw new CryptographicException();
-
+
writer.WriteGeneralizedTime(GeneralTime.Value, omitFractionalSeconds: true);
wroteValue = true;
}
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();
{
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);
{
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();
}