未验证 提交 47ab0dc0 编写于 作者: J Jeremy Barton 提交者: GitHub

Split AsnReader into a class and a ref struct (AsnValueReader)

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.
上级 0dcdbac7
......@@ -15,16 +15,16 @@ internal partial struct AlgorithmIdentifierAsn
{
internal Oid Algorithm;
internal ReadOnlyMemory<byte>? Parameters;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteObjectIdentifier(Algorithm);
if (Parameters.HasValue)
......@@ -39,37 +39,35 @@ internal static AlgorithmIdentifierAsn Decode(ReadOnlyMemory<byte> encoded, AsnE
{
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();
}
......
......@@ -16,22 +16,22 @@ internal partial struct AttributeAsn
{
internal Oid AttrType;
internal ReadOnlyMemory<byte>[] AttrValues;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteObjectIdentifier(AttrType);
writer.PushSetOf();
for (int i = 0; i < AttrValues.Length; i++)
{
writer.WriteEncodedValue(AttrValues[i].Span);
writer.WriteEncodedValue(AttrValues[i].Span);
}
writer.PopSetOf();
......@@ -42,33 +42,30 @@ internal static AttributeAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRul
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
internal static AttributeAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, expectedTag, out AttributeAsn decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, expectedTag, encoded, out AttributeAsn decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out AttributeAsn decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out AttributeAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
Decode(reader, Asn1Tag.Sequence, out decoded);
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
}
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out AttributeAsn decoded)
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out AttributeAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
AsnReader sequenceReader = reader.ReadSequence(expectedTag);
AsnReader collectionReader;
AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
AsnValueReader collectionReader;
ReadOnlySpan<byte> rebindSpan = rebind.Span;
int offset;
ReadOnlySpan<byte> tmpSpan;
decoded.AttrType = sequenceReader.ReadObjectIdentifier();
// Decode SEQUENCE OF for AttrValues
......@@ -79,7 +76,8 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Attribute
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);
}
......
......@@ -16,16 +16,16 @@ internal partial struct CurveAsn
internal ReadOnlyMemory<byte> A;
internal ReadOnlyMemory<byte> B;
internal ReadOnlyMemory<byte>? Seed;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteOctetString(A.Span);
writer.WriteOctetString(B.Span);
......@@ -41,36 +41,33 @@ internal static CurveAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules r
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
internal static CurveAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, expectedTag, out CurveAsn decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, expectedTag, encoded, out CurveAsn decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out CurveAsn decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out CurveAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
Decode(reader, Asn1Tag.Sequence, out decoded);
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
}
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CurveAsn decoded)
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out CurveAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
AsnReader sequenceReader = reader.ReadSequence(expectedTag);
AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
ReadOnlySpan<byte> rebindSpan = rebind.Span;
int offset;
ReadOnlySpan<byte> tmpSpan;
if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpA))
if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
{
decoded.A = tmpA;
decoded.A = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
}
else
{
......@@ -78,9 +75,9 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CurveAsn
}
if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpB))
if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
{
decoded.B = tmpB;
decoded.B = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
}
else
{
......@@ -91,9 +88,9 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out CurveAsn
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
{
......
......@@ -15,16 +15,16 @@ internal partial struct DigestInfoAsn
{
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn DigestAlgorithm;
internal ReadOnlyMemory<byte> Digest;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
DigestAlgorithm.Encode(writer);
writer.WriteOctetString(Digest.Span);
writer.PopSequence(tag);
......@@ -34,37 +34,34 @@ internal static DigestInfoAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRu
{
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
{
......
......@@ -33,7 +33,7 @@ static DirectoryStringAsn()
usedTags.Add(tag, fieldName);
};
ensureUniqueTag(new Asn1Tag(UniversalTagNumber.T61String), "TeletexString");
ensureUniqueTag(new Asn1Tag(UniversalTagNumber.PrintableString), "PrintableString");
ensureUniqueTag(new Asn1Tag((UniversalTagNumber)28), "UniversalString");
......@@ -44,13 +44,13 @@ static DirectoryStringAsn()
internal void Encode(AsnWriter writer)
{
bool wroteValue = false;
bool wroteValue = false;
if (TeletexString != null)
{
if (wroteValue)
throw new CryptographicException();
writer.WriteCharacterString(UniversalTagNumber.T61String, TeletexString);
wroteValue = true;
}
......@@ -59,7 +59,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
writer.WriteCharacterString(UniversalTagNumber.PrintableString, PrintableString);
wroteValue = true;
}
......@@ -68,7 +68,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
// Validator for tag constraint for UniversalString
{
if (!Asn1Tag.TryDecode(UniversalString.Value.Span, out Asn1Tag validateTag, out _) ||
......@@ -86,7 +86,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
writer.WriteCharacterString(UniversalTagNumber.UTF8String, Utf8String);
wroteValue = true;
}
......@@ -95,7 +95,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
writer.WriteCharacterString(UniversalTagNumber.BMPString, BmpString);
wroteValue = true;
}
......@@ -108,21 +108,21 @@ internal void Encode(AsnWriter writer)
internal static DirectoryStringAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, out DirectoryStringAsn decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, encoded, out DirectoryStringAsn decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out DirectoryStringAsn decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out DirectoryStringAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
Asn1Tag tag = reader.PeekTag();
ReadOnlySpan<byte> rebindSpan = rebind.Span;
int offset;
ReadOnlySpan<byte> tmpSpan;
if (tag.HasSameClassAndValue(new Asn1Tag(UniversalTagNumber.T61String)))
{
decoded.TeletexString = reader.ReadCharacterString(UniversalTagNumber.T61String);
......@@ -133,7 +133,8 @@ internal static void Decode(AsnReader reader, out DirectoryStringAsn decoded)
}
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)))
{
......
......@@ -16,16 +16,16 @@ internal partial struct DssParms
internal System.Numerics.BigInteger P;
internal System.Numerics.BigInteger Q;
internal System.Numerics.BigInteger G;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteInteger(P);
writer.WriteInteger(Q);
writer.WriteInteger(G);
......@@ -36,32 +36,26 @@ internal static DssParms Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules r
{
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();
......
......@@ -8,6 +8,7 @@
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
#nullable enable
namespace System.Security.Cryptography.Asn1
{
[StructLayout(LayoutKind.Sequential)]
......@@ -22,14 +23,14 @@ static ECDomainParameters()
var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
{
if (usedTags.TryGetValue(tag, out string existing))
if (usedTags.TryGetValue(tag, out string? existing))
{
throw new InvalidOperationException($"Tag '{tag}' is in use by both '{existing}' and '{fieldName}'");
}
usedTags.Add(tag, fieldName);
};
ensureUniqueTag(Asn1Tag.Sequence, "Specified");
ensureUniqueTag(Asn1Tag.ObjectIdentifier, "Named");
}
......@@ -37,13 +38,13 @@ static ECDomainParameters()
internal void Encode(AsnWriter writer)
{
bool wroteValue = false;
bool wroteValue = false;
if (Specified.HasValue)
{
if (wroteValue)
throw new CryptographicException();
Specified.Value.Encode(writer);
wroteValue = true;
}
......@@ -52,7 +53,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
writer.WriteObjectIdentifier(Named);
wroteValue = true;
}
......@@ -65,25 +66,22 @@ internal void Encode(AsnWriter writer)
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;
}
......
......@@ -17,16 +17,16 @@ internal partial struct ECPrivateKey
internal ReadOnlyMemory<byte> PrivateKey;
internal System.Security.Cryptography.Asn1.ECDomainParameters? Parameters;
internal ReadOnlyMemory<byte>? PublicKey;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteInteger(Version);
writer.WriteOctetString(PrivateKey.Span);
......@@ -52,33 +52,30 @@ internal static ECPrivateKey Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRul
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
internal static ECPrivateKey Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, expectedTag, out ECPrivateKey decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, expectedTag, encoded, out ECPrivateKey decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out ECPrivateKey decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out ECPrivateKey decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
Decode(reader, Asn1Tag.Sequence, out decoded);
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
}
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out ECPrivateKey decoded)
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out ECPrivateKey decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
AsnReader sequenceReader = reader.ReadSequence(expectedTag);
AsnReader explicitReader;
AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
AsnValueReader explicitReader;
ReadOnlySpan<byte> rebindSpan = rebind.Span;
int offset;
ReadOnlySpan<byte> tmpSpan;
if (!sequenceReader.TryReadUInt8(out decoded.Version))
{
......@@ -86,9 +83,9 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out ECPrivate
}
if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpPrivateKey))
if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
{
decoded.PrivateKey = tmpPrivateKey;
decoded.PrivateKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
}
else
{
......@@ -100,7 +97,7 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out ECPrivate
{
explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
System.Security.Cryptography.Asn1.ECDomainParameters tmpParameters;
System.Security.Cryptography.Asn1.ECDomainParameters.Decode(explicitReader, out tmpParameters);
System.Security.Cryptography.Asn1.ECDomainParameters.Decode(ref explicitReader, rebind, out tmpParameters);
decoded.Parameters = tmpParameters;
explicitReader.ThrowIfNotEmpty();
......@@ -111,9 +108,9 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out ECPrivate
{
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
{
......
......@@ -15,16 +15,16 @@ internal partial struct EdiPartyNameAsn
{
internal System.Security.Cryptography.Asn1.DirectoryStringAsn? NameAssigner;
internal System.Security.Cryptography.Asn1.DirectoryStringAsn PartyName;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
if (NameAssigner.HasValue)
{
......@@ -43,39 +43,33 @@ internal static EdiPartyNameAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncoding
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
internal static EdiPartyNameAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, expectedTag, out EdiPartyNameAsn decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, expectedTag, encoded, out EdiPartyNameAsn decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out EdiPartyNameAsn decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out EdiPartyNameAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
Decode(reader, Asn1Tag.Sequence, out decoded);
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
}
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EdiPartyNameAsn decoded)
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out EdiPartyNameAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
AsnReader sequenceReader = reader.ReadSequence(expectedTag);
AsnReader explicitReader;
AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
AsnValueReader explicitReader;
if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
{
explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
System.Security.Cryptography.Asn1.DirectoryStringAsn tmpNameAssigner;
System.Security.Cryptography.Asn1.DirectoryStringAsn.Decode(explicitReader, out tmpNameAssigner);
System.Security.Cryptography.Asn1.DirectoryStringAsn.Decode(ref explicitReader, rebind, out tmpNameAssigner);
decoded.NameAssigner = tmpNameAssigner;
explicitReader.ThrowIfNotEmpty();
......@@ -83,7 +77,7 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EdiPartyN
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();
......
......@@ -15,16 +15,16 @@ internal partial struct EncryptedPrivateKeyInfoAsn
{
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn EncryptionAlgorithm;
internal ReadOnlyMemory<byte> EncryptedData;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
EncryptionAlgorithm.Encode(writer);
writer.WriteOctetString(EncryptedData.Span);
writer.PopSequence(tag);
......@@ -34,37 +34,34 @@ internal static EncryptedPrivateKeyInfoAsn Decode(ReadOnlyMemory<byte> encoded,
{
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
{
......
......@@ -15,16 +15,16 @@ internal partial struct FieldID
{
internal string FieldType;
internal ReadOnlyMemory<byte> Parameters;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteObjectIdentifier(FieldType);
writer.WriteEncodedValue(Parameters.Span);
writer.PopSequence(tag);
......@@ -34,34 +34,32 @@ internal static FieldID Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ru
{
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();
}
......
......@@ -37,7 +37,7 @@ static GeneralNameAsn()
usedTags.Add(tag, fieldName);
};
ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "OtherName");
ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 1), "Rfc822Name");
ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 2), "DnsName");
......@@ -52,13 +52,13 @@ static GeneralNameAsn()
internal void Encode(AsnWriter writer)
{
bool wroteValue = false;
bool wroteValue = false;
if (OtherName.HasValue)
{
if (wroteValue)
throw new CryptographicException();
OtherName.Value.Encode(writer, new Asn1Tag(TagClass.ContextSpecific, 0));
wroteValue = true;
}
......@@ -67,7 +67,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
writer.WriteCharacterString(new Asn1Tag(TagClass.ContextSpecific, 1), UniversalTagNumber.IA5String, Rfc822Name);
wroteValue = true;
}
......@@ -76,7 +76,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
writer.WriteCharacterString(new Asn1Tag(TagClass.ContextSpecific, 2), UniversalTagNumber.IA5String, DnsName);
wroteValue = true;
}
......@@ -85,7 +85,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
// Validator for tag constraint for X400Address
{
if (!Asn1Tag.TryDecode(X400Address.Value.Span, out Asn1Tag validateTag, out _) ||
......@@ -103,7 +103,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 4));
writer.WriteEncodedValue(DirectoryName.Value.Span);
writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 4));
......@@ -114,7 +114,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
EdiPartyName.Value.Encode(writer, new Asn1Tag(TagClass.ContextSpecific, 5));
wroteValue = true;
}
......@@ -123,7 +123,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
writer.WriteCharacterString(new Asn1Tag(TagClass.ContextSpecific, 6), UniversalTagNumber.IA5String, Uri);
wroteValue = true;
}
......@@ -132,7 +132,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
writer.WriteOctetString(new Asn1Tag(TagClass.ContextSpecific, 7), IPAddress.Value.Span);
wroteValue = true;
}
......@@ -141,7 +141,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
writer.WriteObjectIdentifier(new Asn1Tag(TagClass.ContextSpecific, 8), RegisteredId);
wroteValue = true;
}
......@@ -154,26 +154,26 @@ internal void Encode(AsnWriter writer)
internal static GeneralNameAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, out GeneralNameAsn decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, encoded, out GeneralNameAsn decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out GeneralNameAsn decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out GeneralNameAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
Asn1Tag tag = reader.PeekTag();
AsnReader explicitReader;
AsnValueReader explicitReader;
ReadOnlySpan<byte> rebindSpan = rebind.Span;
int offset;
ReadOnlySpan<byte> tmpSpan;
if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
{
System.Security.Cryptography.Asn1.OtherNameAsn tmpOtherName;
System.Security.Cryptography.Asn1.OtherNameAsn.Decode(reader, new Asn1Tag(TagClass.ContextSpecific, 0), out tmpOtherName);
System.Security.Cryptography.Asn1.OtherNameAsn.Decode(ref reader, new Asn1Tag(TagClass.ContextSpecific, 0), rebind, out tmpOtherName);
decoded.OtherName = tmpOtherName;
}
......@@ -187,18 +187,20 @@ internal static void Decode(AsnReader reader, out GeneralNameAsn decoded)
}
else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 3)))
{
decoded.X400Address = reader.ReadEncodedValue();
tmpSpan = reader.ReadEncodedValue();
decoded.X400Address = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
}
else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 4)))
{
explicitReader = reader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 4));
decoded.DirectoryName = explicitReader.ReadEncodedValue();
tmpSpan = explicitReader.ReadEncodedValue();
decoded.DirectoryName = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
explicitReader.ThrowIfNotEmpty();
}
else if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 5)))
{
System.Security.Cryptography.Asn1.EdiPartyNameAsn tmpEdiPartyName;
System.Security.Cryptography.Asn1.EdiPartyNameAsn.Decode(reader, new Asn1Tag(TagClass.ContextSpecific, 5), out tmpEdiPartyName);
System.Security.Cryptography.Asn1.EdiPartyNameAsn.Decode(ref reader, new Asn1Tag(TagClass.ContextSpecific, 5), rebind, out tmpEdiPartyName);
decoded.EdiPartyName = tmpEdiPartyName;
}
......@@ -209,9 +211,9 @@ internal static void Decode(AsnReader reader, out GeneralNameAsn decoded)
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
{
......
......@@ -14,44 +14,45 @@ namespace System.Security.Cryptography.Asn1
internal partial struct OaepParamsAsn
{
private static readonly byte[] s_defaultHashFunc = { 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 };
private static readonly byte[] s_defaultMaskGenFunc = { 0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 };
private static readonly byte[] s_defaultPSourceFunc = { 0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x09, 0x04, 0x00 };
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashFunc;
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenFunc;
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn PSourceFunc;
#if DEBUG
static OaepParamsAsn()
{
OaepParamsAsn decoded = default;
AsnReader reader;
ReadOnlyMemory<byte> rebind = default;
AsnValueReader reader;
reader = new AsnReader(s_defaultHashFunc, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.HashFunc);
reader = new AsnValueReader(s_defaultHashFunc, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashFunc);
reader.ThrowIfNotEmpty();
reader = new AsnReader(s_defaultMaskGenFunc, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.MaskGenFunc);
reader = new AsnValueReader(s_defaultMaskGenFunc, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.MaskGenFunc);
reader.ThrowIfNotEmpty();
reader = new AsnReader(s_defaultPSourceFunc, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.PSourceFunc);
reader = new AsnValueReader(s_defaultPSourceFunc, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.PSourceFunc);
reader.ThrowIfNotEmpty();
}
#endif
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
// DEFAULT value handler for HashFunc.
{
......@@ -63,7 +64,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
if (!encoded.SequenceEqual(s_defaultHashFunc))
{
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
writer.WriteEncodedValue(encoded.ToArray());
writer.WriteEncodedValue(encoded);
writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
}
}
......@@ -80,7 +81,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
if (!encoded.SequenceEqual(s_defaultMaskGenFunc))
{
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
writer.WriteEncodedValue(encoded.ToArray());
writer.WriteEncodedValue(encoded);
writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
}
}
......@@ -97,7 +98,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
if (!encoded.SequenceEqual(s_defaultPSourceFunc))
{
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
writer.WriteEncodedValue(encoded.ToArray());
writer.WriteEncodedValue(encoded);
writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
}
}
......@@ -110,71 +111,65 @@ internal static OaepParamsAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRu
{
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);
}
......
......@@ -15,16 +15,16 @@ internal partial struct OtherNameAsn
{
internal string TypeId;
internal ReadOnlyMemory<byte> Value;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteObjectIdentifier(TypeId);
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
writer.WriteEncodedValue(Value.Span);
......@@ -36,37 +36,35 @@ internal static OtherNameAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRul
{
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();
......
......@@ -15,16 +15,16 @@ internal partial struct PBEParameter
{
internal ReadOnlyMemory<byte> Salt;
internal int IterationCount;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteOctetString(Salt.Span);
writer.WriteInteger(IterationCount);
writer.PopSequence(tag);
......@@ -34,36 +34,33 @@ internal static PBEParameter Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRul
{
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
{
......
......@@ -15,16 +15,16 @@ internal partial struct PBES2Params
{
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn KeyDerivationFunc;
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn EncryptionScheme;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
KeyDerivationFunc.Encode(writer);
EncryptionScheme.Encode(writer);
writer.PopSequence(tag);
......@@ -34,34 +34,28 @@ internal static PBES2Params Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRule
{
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();
}
......
......@@ -14,33 +14,34 @@ namespace System.Security.Cryptography.Asn1
internal partial struct Pbkdf2Params
{
private static readonly byte[] s_defaultPrf = { 0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07, 0x05, 0x00 };
internal System.Security.Cryptography.Asn1.Pbkdf2SaltChoice Salt;
internal int IterationCount;
internal byte? KeyLength;
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn Prf;
#if DEBUG
static Pbkdf2Params()
{
Pbkdf2Params decoded = default;
AsnReader reader;
ReadOnlyMemory<byte> rebind = default;
AsnValueReader reader;
reader = new AsnReader(s_defaultPrf, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.Prf);
reader = new AsnValueReader(s_defaultPrf, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.Prf);
reader.ThrowIfNotEmpty();
}
#endif
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
Salt.Encode(writer);
writer.WriteInteger(IterationCount);
......@@ -49,7 +50,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
writer.WriteInteger(KeyLength.Value);
}
// DEFAULT value handler for Prf.
{
using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
......@@ -59,7 +60,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
if (!encoded.SequenceEqual(s_defaultPrf))
{
writer.WriteEncodedValue(encoded.ToArray());
writer.WriteEncodedValue(encoded);
}
}
}
......@@ -71,34 +72,28 @@ internal static Pbkdf2Params Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRul
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
internal static Pbkdf2Params Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, expectedTag, out Pbkdf2Params decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, expectedTag, encoded, out Pbkdf2Params decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out Pbkdf2Params decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out Pbkdf2Params decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
Decode(reader, Asn1Tag.Sequence, out decoded);
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
}
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Pbkdf2Params decoded)
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out Pbkdf2Params decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
AsnReader sequenceReader = reader.ReadSequence(expectedTag);
AsnReader defaultReader;
System.Security.Cryptography.Asn1.Pbkdf2SaltChoice.Decode(sequenceReader, out decoded.Salt);
AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
AsnValueReader defaultReader;
System.Security.Cryptography.Asn1.Pbkdf2SaltChoice.Decode(ref sequenceReader, rebind, out decoded.Salt);
if (!sequenceReader.TryReadInt32(out decoded.IterationCount))
{
......@@ -123,12 +118,12 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Pbkdf2Par
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);
}
......
......@@ -8,6 +8,7 @@
using System.Security.Cryptography;
using System.Security.Cryptography.Asn1;
#nullable enable
namespace System.Security.Cryptography.Asn1
{
[StructLayout(LayoutKind.Sequential)]
......@@ -22,14 +23,14 @@ static Pbkdf2SaltChoice()
var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
{
if (usedTags.TryGetValue(tag, out string existing))
if (usedTags.TryGetValue(tag, out string? existing))
{
throw new InvalidOperationException($"Tag '{tag}' is in use by both '{existing}' and '{fieldName}'");
}
usedTags.Add(tag, fieldName);
};
ensureUniqueTag(Asn1Tag.PrimitiveOctetString, "Specified");
ensureUniqueTag(Asn1Tag.Sequence, "OtherSource");
}
......@@ -37,13 +38,13 @@ static Pbkdf2SaltChoice()
internal void Encode(AsnWriter writer)
{
bool wroteValue = false;
bool wroteValue = false;
if (Specified.HasValue)
{
if (wroteValue)
throw new CryptographicException();
writer.WriteOctetString(Specified.Value.Span);
wroteValue = true;
}
......@@ -52,7 +53,7 @@ internal void Encode(AsnWriter writer)
{
if (wroteValue)
throw new CryptographicException();
OtherSource.Value.Encode(writer);
wroteValue = true;
}
......@@ -65,27 +66,27 @@ internal void Encode(AsnWriter writer)
internal static Pbkdf2SaltChoice Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, out Pbkdf2SaltChoice decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, encoded, out Pbkdf2SaltChoice decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out Pbkdf2SaltChoice decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out Pbkdf2SaltChoice decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
Asn1Tag tag = reader.PeekTag();
ReadOnlySpan<byte> rebindSpan = rebind.Span;
int offset;
ReadOnlySpan<byte> tmpSpan;
if (tag.HasSameClassAndValue(Asn1Tag.PrimitiveOctetString))
{
if (reader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpSpecified))
if (reader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
{
decoded.Specified = tmpSpecified;
decoded.Specified = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
}
else
{
......@@ -96,7 +97,7 @@ internal static void Decode(AsnReader reader, out Pbkdf2SaltChoice decoded)
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;
}
......
......@@ -15,16 +15,16 @@ internal partial struct CertBagAsn
{
internal string CertId;
internal ReadOnlyMemory<byte> CertValue;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteObjectIdentifier(CertId);
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
writer.WriteEncodedValue(CertValue.Span);
......@@ -36,37 +36,35 @@ internal static CertBagAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules
{
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();
......
......@@ -14,18 +14,18 @@ namespace System.Security.Cryptography.Asn1.Pkcs12
internal partial struct MacData
{
private static readonly byte[] s_defaultIterationCount = { 0x02, 0x01, 0x01 };
internal System.Security.Cryptography.Asn1.DigestInfoAsn Mac;
internal ReadOnlyMemory<byte> MacSalt;
internal int IterationCount;
#if DEBUG
static MacData()
{
MacData decoded = default;
AsnReader reader;
AsnValueReader reader;
reader = new AsnReader(s_defaultIterationCount, AsnEncodingRules.DER);
reader = new AsnValueReader(s_defaultIterationCount, AsnEncodingRules.DER);
if (!reader.TryReadInt32(out decoded.IterationCount))
{
......@@ -35,19 +35,19 @@ static MacData()
reader.ThrowIfNotEmpty();
}
#endif
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
Mac.Encode(writer);
writer.WriteOctetString(MacSalt.Span);
// DEFAULT value handler for IterationCount.
{
using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
......@@ -57,7 +57,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
if (!encoded.SequenceEqual(s_defaultIterationCount))
{
writer.WriteEncodedValue(encoded.ToArray());
writer.WriteEncodedValue(encoded);
}
}
}
......@@ -69,38 +69,35 @@ internal static MacData Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ru
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
internal static MacData Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, expectedTag, out MacData decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, expectedTag, encoded, out MacData decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out MacData decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out MacData decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
Decode(reader, Asn1Tag.Sequence, out decoded);
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
}
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out MacData decoded)
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out MacData decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
AsnReader sequenceReader = reader.ReadSequence(expectedTag);
AsnReader defaultReader;
System.Security.Cryptography.Asn1.DigestInfoAsn.Decode(sequenceReader, out decoded.Mac);
AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
AsnValueReader defaultReader;
ReadOnlySpan<byte> rebindSpan = rebind.Span;
int offset;
ReadOnlySpan<byte> tmpSpan;
System.Security.Cryptography.Asn1.DigestInfoAsn.Decode(ref sequenceReader, rebind, out decoded.Mac);
if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpMacSalt))
if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
{
decoded.MacSalt = tmpMacSalt;
decoded.MacSalt = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
}
else
{
......@@ -119,7 +116,7 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out MacData d
}
else
{
defaultReader = new AsnReader(s_defaultIterationCount, AsnEncodingRules.DER);
defaultReader = new AsnValueReader(s_defaultIterationCount, AsnEncodingRules.DER);
if (!defaultReader.TryReadInt32(out decoded.IterationCount))
{
......
......@@ -16,16 +16,16 @@ internal partial struct PfxAsn
internal byte Version;
internal System.Security.Cryptography.Asn1.Pkcs7.ContentInfoAsn AuthSafe;
internal System.Security.Cryptography.Asn1.Pkcs12.MacData? MacData;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteInteger(Version);
AuthSafe.Encode(writer);
......@@ -41,44 +41,38 @@ internal static PfxAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules rul
{
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;
}
......
......@@ -17,16 +17,16 @@ internal partial struct SafeBagAsn
internal string BagId;
internal ReadOnlyMemory<byte> BagValue;
internal System.Security.Cryptography.Asn1.AttributeAsn[] BagAttributes;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteObjectIdentifier(BagId);
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
writer.WriteEncodedValue(BagValue.Span);
......@@ -38,7 +38,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
writer.PushSetOf();
for (int i = 0; i < BagAttributes.Length; i++)
{
BagAttributes[i].Encode(writer);
BagAttributes[i].Encode(writer);
}
writer.PopSetOf();
......@@ -51,38 +51,36 @@ internal static SafeBagAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
internal static SafeBagAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, expectedTag, out SafeBagAsn decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, expectedTag, encoded, out SafeBagAsn decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out SafeBagAsn decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out SafeBagAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
Decode(reader, Asn1Tag.Sequence, out decoded);
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
}
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SafeBagAsn decoded)
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out SafeBagAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
AsnReader sequenceReader = reader.ReadSequence(expectedTag);
AsnReader explicitReader;
AsnReader collectionReader;
AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
AsnValueReader explicitReader;
AsnValueReader collectionReader;
ReadOnlySpan<byte> rebindSpan = rebind.Span;
int offset;
ReadOnlySpan<byte> tmpSpan;
decoded.BagId = sequenceReader.ReadObjectIdentifierAsString();
explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
decoded.BagValue = explicitReader.ReadEncodedValue();
tmpSpan = explicitReader.ReadEncodedValue();
decoded.BagValue = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
explicitReader.ThrowIfNotEmpty();
......@@ -97,7 +95,7 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out SafeBagAs
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);
}
......
......@@ -15,16 +15,16 @@ internal partial struct ContentInfoAsn
{
internal string ContentType;
internal ReadOnlyMemory<byte> Content;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteObjectIdentifier(ContentType);
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
writer.WriteEncodedValue(Content.Span);
......@@ -36,37 +36,35 @@ internal static ContentInfoAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingR
{
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();
......
......@@ -16,16 +16,16 @@ internal partial struct EncryptedContentInfoAsn
internal string ContentType;
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn ContentEncryptionAlgorithm;
internal ReadOnlyMemory<byte>? EncryptedContent;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteObjectIdentifier(ContentType);
ContentEncryptionAlgorithm.Encode(writer);
......@@ -41,41 +41,38 @@ internal static EncryptedContentInfoAsn Decode(ReadOnlyMemory<byte> encoded, Asn
{
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
{
......
......@@ -17,16 +17,16 @@ internal partial struct EncryptedDataAsn
internal int Version;
internal System.Security.Cryptography.Asn1.Pkcs7.EncryptedContentInfoAsn EncryptedContentInfo;
internal System.Security.Cryptography.Asn1.AttributeAsn[] UnprotectedAttributes;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteInteger(Version);
EncryptedContentInfo.Encode(writer);
......@@ -36,7 +36,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
for (int i = 0; i < UnprotectedAttributes.Length; i++)
{
UnprotectedAttributes[i].Encode(writer);
UnprotectedAttributes[i].Encode(writer);
}
writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 1));
......@@ -49,40 +49,34 @@ internal static EncryptedDataAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodin
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
internal static EncryptedDataAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, expectedTag, out EncryptedDataAsn decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, expectedTag, encoded, out EncryptedDataAsn decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out EncryptedDataAsn decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out EncryptedDataAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
Decode(reader, Asn1Tag.Sequence, out decoded);
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
}
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out EncryptedDataAsn decoded)
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out EncryptedDataAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
AsnReader sequenceReader = reader.ReadSequence(expectedTag);
AsnReader collectionReader;
AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
AsnValueReader collectionReader;
if (!sequenceReader.TryReadInt32(out decoded.Version))
{
sequenceReader.ThrowIfNotEmpty();
}
System.Security.Cryptography.Asn1.Pkcs7.EncryptedContentInfoAsn.Decode(sequenceReader, out decoded.EncryptedContentInfo);
System.Security.Cryptography.Asn1.Pkcs7.EncryptedContentInfoAsn.Decode(ref sequenceReader, rebind, out decoded.EncryptedContentInfo);
if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
{
......@@ -95,7 +89,7 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Encrypted
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);
}
......
......@@ -18,16 +18,16 @@ internal partial struct PrivateKeyInfoAsn
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn PrivateKeyAlgorithm;
internal ReadOnlyMemory<byte> PrivateKey;
internal System.Security.Cryptography.Asn1.AttributeAsn[] Attributes;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteInteger(Version);
PrivateKeyAlgorithm.Encode(writer);
writer.WriteOctetString(PrivateKey.Span);
......@@ -38,7 +38,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
writer.PushSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
for (int i = 0; i < Attributes.Length; i++)
{
Attributes[i].Encode(writer);
Attributes[i].Encode(writer);
}
writer.PopSetOf(new Asn1Tag(TagClass.ContextSpecific, 0));
......@@ -51,44 +51,41 @@ internal static PrivateKeyInfoAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodi
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
internal static PrivateKeyInfoAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, expectedTag, out PrivateKeyInfoAsn decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, expectedTag, encoded, out PrivateKeyInfoAsn decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out PrivateKeyInfoAsn decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out PrivateKeyInfoAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
Decode(reader, Asn1Tag.Sequence, out decoded);
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
}
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PrivateKeyInfoAsn decoded)
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out PrivateKeyInfoAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
AsnReader sequenceReader = reader.ReadSequence(expectedTag);
AsnReader collectionReader;
AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
AsnValueReader collectionReader;
ReadOnlySpan<byte> rebindSpan = rebind.Span;
int offset;
ReadOnlySpan<byte> tmpSpan;
if (!sequenceReader.TryReadUInt8(out decoded.Version))
{
sequenceReader.ThrowIfNotEmpty();
}
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(sequenceReader, out decoded.PrivateKeyAlgorithm);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.PrivateKeyAlgorithm);
if (sequenceReader.TryReadPrimitiveOctetStringBytes(out ReadOnlyMemory<byte> tmpPrivateKey))
if (sequenceReader.TryReadPrimitiveOctetStringBytes(out tmpSpan))
{
decoded.PrivateKey = tmpPrivateKey;
decoded.PrivateKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
}
else
{
......@@ -107,7 +104,7 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PrivateKe
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);
}
......
......@@ -14,33 +14,34 @@ namespace System.Security.Cryptography.Asn1
internal partial struct PssParamsAsn
{
private static readonly byte[] s_defaultHashAlgorithm = { 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 };
private static readonly byte[] s_defaultMaskGenAlgorithm = { 0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00 };
private static readonly byte[] s_defaultSaltLength = { 0x02, 0x01, 0x14 };
private static readonly byte[] s_defaultTrailerField = { 0x02, 0x01, 0x01 };
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm;
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenAlgorithm;
internal int SaltLength;
internal int TrailerField;
#if DEBUG
static PssParamsAsn()
{
PssParamsAsn decoded = default;
AsnReader reader;
ReadOnlyMemory<byte> rebind = default;
AsnValueReader reader;
reader = new AsnReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.HashAlgorithm);
reader = new AsnValueReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashAlgorithm);
reader.ThrowIfNotEmpty();
reader = new AsnReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(reader, out decoded.MaskGenAlgorithm);
reader = new AsnValueReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.MaskGenAlgorithm);
reader.ThrowIfNotEmpty();
reader = new AsnReader(s_defaultSaltLength, AsnEncodingRules.DER);
reader = new AsnValueReader(s_defaultSaltLength, AsnEncodingRules.DER);
if (!reader.TryReadInt32(out decoded.SaltLength))
{
......@@ -49,7 +50,7 @@ static PssParamsAsn()
reader.ThrowIfNotEmpty();
reader = new AsnReader(s_defaultTrailerField, AsnEncodingRules.DER);
reader = new AsnValueReader(s_defaultTrailerField, AsnEncodingRules.DER);
if (!reader.TryReadInt32(out decoded.TrailerField))
{
......@@ -59,16 +60,16 @@ static PssParamsAsn()
reader.ThrowIfNotEmpty();
}
#endif
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
// DEFAULT value handler for HashAlgorithm.
{
......@@ -80,7 +81,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
if (!encoded.SequenceEqual(s_defaultHashAlgorithm))
{
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
writer.WriteEncodedValue(encoded.ToArray());
writer.WriteEncodedValue(encoded);
writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
}
}
......@@ -97,7 +98,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
if (!encoded.SequenceEqual(s_defaultMaskGenAlgorithm))
{
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
writer.WriteEncodedValue(encoded.ToArray());
writer.WriteEncodedValue(encoded);
writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
}
}
......@@ -114,7 +115,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
if (!encoded.SequenceEqual(s_defaultSaltLength))
{
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
writer.WriteEncodedValue(encoded.ToArray());
writer.WriteEncodedValue(encoded);
writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 2));
}
}
......@@ -131,7 +132,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
if (!encoded.SequenceEqual(s_defaultTrailerField))
{
writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
writer.WriteEncodedValue(encoded.ToArray());
writer.WriteEncodedValue(encoded);
writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 3));
}
}
......@@ -144,58 +145,52 @@ internal static PssParamsAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRul
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
internal static PssParamsAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, expectedTag, out PssParamsAsn decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, expectedTag, encoded, out PssParamsAsn decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out PssParamsAsn decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out PssParamsAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
Decode(reader, Asn1Tag.Sequence, out decoded);
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
}
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PssParamsAsn decoded)
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out PssParamsAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
AsnReader sequenceReader = reader.ReadSequence(expectedTag);
AsnReader explicitReader;
AsnReader defaultReader;
AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
AsnValueReader explicitReader;
AsnValueReader defaultReader;
if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0)))
{
explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0));
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(explicitReader, out decoded.HashAlgorithm);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref explicitReader, rebind, out decoded.HashAlgorithm);
explicitReader.ThrowIfNotEmpty();
}
else
{
defaultReader = new AsnReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.HashAlgorithm);
defaultReader = new AsnValueReader(s_defaultHashAlgorithm, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.HashAlgorithm);
}
if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1)))
{
explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 1));
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(explicitReader, out decoded.MaskGenAlgorithm);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref explicitReader, rebind, out decoded.MaskGenAlgorithm);
explicitReader.ThrowIfNotEmpty();
}
else
{
defaultReader = new AsnReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(defaultReader, out decoded.MaskGenAlgorithm);
defaultReader = new AsnValueReader(s_defaultMaskGenAlgorithm, AsnEncodingRules.DER);
System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.MaskGenAlgorithm);
}
......@@ -212,7 +207,7 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PssParams
}
else
{
defaultReader = new AsnReader(s_defaultSaltLength, AsnEncodingRules.DER);
defaultReader = new AsnValueReader(s_defaultSaltLength, AsnEncodingRules.DER);
if (!defaultReader.TryReadInt32(out decoded.SaltLength))
{
......@@ -235,7 +230,7 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out PssParams
}
else
{
defaultReader = new AsnReader(s_defaultTrailerField, AsnEncodingRules.DER);
defaultReader = new AsnValueReader(s_defaultTrailerField, AsnEncodingRules.DER);
if (!defaultReader.TryReadInt32(out decoded.TrailerField))
{
......
......@@ -22,16 +22,16 @@ internal partial struct RSAPrivateKeyAsn
internal System.Numerics.BigInteger Exponent1;
internal System.Numerics.BigInteger Exponent2;
internal System.Numerics.BigInteger Coefficient;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteInteger(Version);
writer.WriteInteger(Modulus);
writer.WriteInteger(PublicExponent);
......@@ -48,32 +48,26 @@ internal static RSAPrivateKeyAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodin
{
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))
{
......
......@@ -15,16 +15,16 @@ internal partial struct RSAPublicKeyAsn
{
internal System.Numerics.BigInteger Modulus;
internal System.Numerics.BigInteger PublicExponent;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteInteger(Modulus);
writer.WriteInteger(PublicExponent);
writer.PopSequence(tag);
......@@ -34,32 +34,26 @@ internal static RSAPublicKeyAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncoding
{
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();
......
......@@ -15,16 +15,16 @@ internal partial struct Rc2CbcParameters
{
internal int Rc2Version;
internal ReadOnlyMemory<byte> Iv;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteInteger(Rc2Version);
writer.WriteOctetString(Iv.Span);
writer.PopSequence(tag);
......@@ -34,32 +34,29 @@ internal static Rc2CbcParameters Decode(ReadOnlyMemory<byte> encoded, AsnEncodin
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
internal static Rc2CbcParameters Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, expectedTag, out Rc2CbcParameters decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, expectedTag, encoded, out Rc2CbcParameters decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out Rc2CbcParameters decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out Rc2CbcParameters decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
Decode(reader, Asn1Tag.Sequence, out decoded);
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
}
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Rc2CbcParameters decoded)
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out Rc2CbcParameters decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
AsnReader sequenceReader = reader.ReadSequence(expectedTag);
AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
ReadOnlySpan<byte> rebindSpan = rebind.Span;
int offset;
ReadOnlySpan<byte> tmpSpan;
if (!sequenceReader.TryReadInt32(out decoded.Rc2Version))
{
......@@ -67,9 +64,9 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out Rc2CbcPar
}
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
{
......
......@@ -20,16 +20,16 @@ internal partial struct SpecifiedECDomain
internal ReadOnlyMemory<byte> Order;
internal ReadOnlyMemory<byte>? Cofactor;
internal Oid Hash;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteInteger(Version);
FieldID.Encode(writer);
Curve.Encode(writer);
......@@ -54,55 +54,54 @@ internal static SpecifiedECDomain Decode(ReadOnlyMemory<byte> encoded, AsnEncodi
{
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();
}
......
......@@ -15,16 +15,16 @@ internal partial struct SubjectPublicKeyInfoAsn
{
internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn Algorithm;
internal ReadOnlyMemory<byte> SubjectPublicKey;
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
Algorithm.Encode(writer);
writer.WriteBitString(SubjectPublicKey.Span);
writer.PopSequence(tag);
......@@ -34,37 +34,34 @@ internal static SubjectPublicKeyInfoAsn Decode(ReadOnlyMemory<byte> encoded, Asn
{
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
{
......
......@@ -14,34 +14,34 @@ namespace System.Security.Cryptography.Asn1
internal partial struct X509ExtensionAsn
{
private static readonly byte[] s_defaultCritical = { 0x01, 0x01, 0x00 };
internal Oid ExtnId;
internal bool Critical;
internal ReadOnlyMemory<byte> ExtnValue;
#if DEBUG
static X509ExtensionAsn()
{
X509ExtensionAsn decoded = default;
AsnReader reader;
AsnValueReader reader;
reader = new AsnReader(s_defaultCritical, AsnEncodingRules.DER);
reader = new AsnValueReader(s_defaultCritical, AsnEncodingRules.DER);
decoded.Critical = reader.ReadBoolean();
reader.ThrowIfNotEmpty();
}
#endif
internal void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}
internal void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);
writer.WriteObjectIdentifier(ExtnId);
// DEFAULT value handler for Critical.
{
using (AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER))
......@@ -51,7 +51,7 @@ internal void Encode(AsnWriter writer, Asn1Tag tag)
if (!encoded.SequenceEqual(s_defaultCritical))
{
writer.WriteEncodedValue(encoded.ToArray());
writer.WriteEncodedValue(encoded);
}
}
}
......@@ -64,33 +64,30 @@ internal static X509ExtensionAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodin
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
}
internal static X509ExtensionAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
{
AsnReader reader = new AsnReader(encoded, ruleSet);
Decode(reader, expectedTag, out X509ExtensionAsn decoded);
AsnValueReader reader = new AsnValueReader(encoded.Span, ruleSet);
Decode(ref reader, expectedTag, encoded, out X509ExtensionAsn decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
internal static void Decode(AsnReader reader, out X509ExtensionAsn decoded)
internal static void Decode(ref AsnValueReader reader, ReadOnlyMemory<byte> rebind, out X509ExtensionAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
Decode(reader, Asn1Tag.Sequence, out decoded);
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
}
internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out X509ExtensionAsn decoded)
internal static void Decode(ref AsnValueReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out X509ExtensionAsn decoded)
{
if (reader == null)
throw new ArgumentNullException(nameof(reader));
decoded = default;
AsnReader sequenceReader = reader.ReadSequence(expectedTag);
AsnReader defaultReader;
AsnValueReader sequenceReader = reader.ReadSequence(expectedTag);
AsnValueReader defaultReader;
ReadOnlySpan<byte> rebindSpan = rebind.Span;
int offset;
ReadOnlySpan<byte> tmpSpan;
decoded.ExtnId = sequenceReader.ReadObjectIdentifier();
if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Boolean))
......@@ -99,14 +96,14 @@ internal static void Decode(AsnReader reader, Asn1Tag expectedTag, out X509Exten
}
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
{
......
......@@ -7,7 +7,7 @@
#nullable enable
namespace System.Security.Cryptography.Asn1
{
internal partial class AsnReader
internal ref partial struct AsnValueReader
{
/// <summary>
/// Reads the next value as a Boolean with tag UNIVERSAL 1.
......@@ -49,7 +49,7 @@ public bool ReadBoolean(Asn1Tag expectedTag)
Debug.Assert(length.HasValue);
bool value = ReadBooleanValue(
Slice(_data, headerLength, length.Value).Span,
Slice(_data, headerLength, length.Value),
RuleSet);
_data = _data.Slice(headerLength + length.Value);
......@@ -83,4 +83,42 @@ public bool ReadBoolean(Asn1Tag expectedTag)
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;
}
}
}
......@@ -7,11 +7,11 @@
namespace System.Security.Cryptography.Asn1
{
internal partial class AsnReader
internal ref partial struct AsnValueReader
{
/// <summary>
/// Reads the next value as an Enumerated value with tag UNIVERSAL 10,
/// returning the contents as a <see cref="ReadOnlyMemory{T}"/> over the original data.
/// returning the contents as a <see cref="ReadOnlySpan{T}"/> over the original data.
/// </summary>
/// <returns>
/// The bytes of the Enumerated value, in signed big-endian form.
......@@ -22,12 +22,12 @@ internal partial class AsnReader
/// the contents are not valid under the current encoding rules
/// </exception>
/// <seealso cref="ReadEnumeratedValue{TEnum}()"/>
public ReadOnlyMemory<byte> ReadEnumeratedBytes() =>
public ReadOnlySpan<byte> ReadEnumeratedBytes() =>
ReadEnumeratedBytes(Asn1Tag.Enumerated);
/// <summary>
/// Reads the next value as a Enumerated with a specified tag, returning the contents
/// as a <see cref="ReadOnlyMemory{T}"/> over the original data.
/// as a <see cref="ReadOnlySpan{T}"/> over the original data.
/// </summary>
/// <param name="expectedTag">The tag to check for before reading.</param>
/// <returns>
......@@ -45,10 +45,10 @@ internal partial class AsnReader
/// the method
/// </exception>
/// <seealso cref="ReadEnumeratedValue{TEnum}(Asn1Tag)"/>
public ReadOnlyMemory<byte> ReadEnumeratedBytes(Asn1Tag expectedTag)
public ReadOnlySpan<byte> ReadEnumeratedBytes(Asn1Tag expectedTag)
{
// T-REC-X.690-201508 sec 8.4 says the contents are the same as for integers.
ReadOnlyMemory<byte> contents =
ReadOnlySpan<byte> contents =
GetIntegerContents(expectedTag, UniversalTagNumber.Enumerated, out int headerLength);
_data = _data.Slice(headerLength + contents.Length);
......@@ -222,4 +222,180 @@ public Enum ReadEnumeratedValue(Asn1Tag expectedTag, Type tEnum)
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;
}
}
}
......@@ -9,7 +9,7 @@
#nullable enable
namespace System.Security.Cryptography.Asn1
{
internal partial class AsnReader
internal ref partial struct AsnValueReader
{
/// <summary>
/// Reads the next value as a GeneralizedTime with tag UNIVERSAL 24.
......@@ -56,10 +56,16 @@ internal partial class AsnReader
public DateTimeOffset ReadGeneralizedTime(Asn1Tag expectedTag, bool disallowFractions = false)
{
byte[]? rented = null;
Span<byte> tmpSpace;
// An X.509 time is 15 characters (yyyyMMddHHmmssZ), beyond that is fractions (no limit) or
// BER specified offset.
Span<byte> tmpSpace = stackalloc byte[64];
unsafe
{
// An X.509 time is 15 characters (yyyyMMddHHmmssZ), beyond that is fractions (no limit) or
// BER specified offset.
const int StackBufSize = 64;
byte* stackBuf = stackalloc byte[StackBufSize];
tmpSpace = new Span<byte>(stackBuf, StackBufSize);
}
ReadOnlySpan<byte> contents = GetOctetStringContents(
expectedTag,
......@@ -406,4 +412,57 @@ public DateTimeOffset ReadGeneralizedTime(Asn1Tag expectedTag, bool disallowFrac
}
}
}
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;
}
}
}
......@@ -7,7 +7,7 @@
namespace System.Security.Cryptography.Asn1
{
internal partial class AsnReader
internal ref partial struct AsnValueReader
{
/// <summary>
/// Reads the next value as a NamedBitList with tag UNIVERSAL 3, converting it to the
......@@ -165,8 +165,14 @@ public Enum ReadNamedBitListValue(Asn1Tag expectedTag, Type tFlagsEnum)
}
int sizeLimit = Marshal.SizeOf(backingType);
Span<byte> stackSpan = stackalloc byte[sizeLimit];
ReadOnlyMemory<byte> saveData = _data;
ReadOnlySpan<byte> saveData = _data;
Span<byte> stackSpan;
unsafe
{
byte* stackPtr = stackalloc byte[sizeLimit];
stackSpan = new Span<byte>(stackPtr, sizeLimit);
}
// If TryCopyBitStringBytes succeeds but anything else fails _data will have moved,
// so if anything throws here just move _data back to what it was.
......@@ -265,4 +271,157 @@ private static long InterpretNamedBitListReversed(ReadOnlySpan<byte> valueSpan)
return accum;
}
}
internal partial class AsnReader
{
/// <summary>
/// Reads the next value as a NamedBitList with tag UNIVERSAL 3, converting it to the
/// [<see cref="FlagsAttribute"/>] enum specfied by <typeparamref name="TFlagsEnum"/>.
/// </summary>
/// <typeparam name="TFlagsEnum">Destination enum type</typeparam>
/// <returns>
/// the NamedBitList value converted to a <typeparamref name="TFlagsEnum"/>.
/// </returns>
/// <exception cref="CryptographicException">
/// the next value does not have the correct tag --OR--
/// the length encoding is not valid under the current encoding rules --OR--
/// the contents are not valid under the current encoding rules --OR--
/// the encoded value is too big to fit in a <typeparamref name="TFlagsEnum"/> value
/// </exception>
/// <exception cref="ArgumentException">
/// <typeparamref name="TFlagsEnum"/> is not an enum type --OR--
/// <typeparamref name="TFlagsEnum"/> was not declared with <see cref="FlagsAttribute"/>
/// </exception>
/// <seealso cref="ReadNamedBitListValue{TFlagsEnum}(Asn1Tag)"/>
public TFlagsEnum ReadNamedBitListValue<TFlagsEnum>() where TFlagsEnum : struct =>
ReadNamedBitListValue<TFlagsEnum>(Asn1Tag.PrimitiveBitString);
/// <summary>
/// Reads the next value as a NamedBitList with tag UNIVERSAL 3, converting it to the
/// [<see cref="FlagsAttribute"/>] enum specfied by <typeparamref name="TFlagsEnum"/>.
/// </summary>
/// <param name="expectedTag">The tag to check for before reading.</param>
/// <typeparam name="TFlagsEnum">Destination enum type</typeparam>
/// <returns>
/// the NamedBitList value converted to a <typeparamref name="TFlagsEnum"/>.
/// </returns>
/// <exception cref="CryptographicException">
/// the next value does not have the correct tag --OR--
/// the length encoding is not valid under the current encoding rules --OR--
/// the contents are not valid under the current encoding rules --OR--
/// the encoded value is too big to fit in a <typeparamref name="TFlagsEnum"/> value
/// </exception>
/// <exception cref="ArgumentException">
/// <typeparamref name="TFlagsEnum"/> is not an enum type --OR--
/// <typeparamref name="TFlagsEnum"/> was not declared with <see cref="FlagsAttribute"/>
/// --OR--
/// <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
/// <see cref="TagClass.Universal"/>, but
/// <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
/// the method
/// </exception>
/// <remarks>
/// The bit alignment performed by this method is to interpret the most significant bit
/// in the first byte of the value as the least significant bit in <typeparamref name="TFlagsEnum"/>,
/// with bits increasing in value until the least significant bit of the first byte, proceeding
/// with the most significant bit of the second byte, and so on. Under this scheme, the following
/// ASN.1 type declaration and C# enumeration can be used together:
///
/// <code>
/// KeyUsage ::= BIT STRING {
/// digitalSignature (0),
/// nonRepudiation (1),
/// keyEncipherment (2),
/// dataEncipherment (3),
/// keyAgreement (4),
/// keyCertSign (5),
/// cRLSign (6),
/// encipherOnly (7),
/// decipherOnly (8) }
/// </code>
///
/// <code>
/// [Flags]
/// enum KeyUsage
/// {
/// None = 0,
/// DigitalSignature = 1 &lt;&lt; (0),
/// NonRepudiation = 1 &lt;&lt; (1),
/// KeyEncipherment = 1 &lt;&lt; (2),
/// DataEncipherment = 1 &lt;&lt; (3),
/// KeyAgreement = 1 &lt;&lt; (4),
/// KeyCertSign = 1 &lt;&lt; (5),
/// CrlSign = 1 &lt;&lt; (6),
/// EncipherOnly = 1 &lt;&lt; (7),
/// DecipherOnly = 1 &lt;&lt; (8),
/// }
/// </code>
///
/// Note that while the example here uses the KeyUsage NamedBitList from
/// <a href="https://tools.ietf.org/html/rfc3280#section-4.2.1.3">RFC 3280 (4.2.1.3)</a>,
/// the example enum uses values thar are different from
/// System.Security.Cryptography.X509Certificates.X509KeyUsageFlags.
/// </remarks>
public TFlagsEnum ReadNamedBitListValue<TFlagsEnum>(Asn1Tag expectedTag) where TFlagsEnum : struct
{
Type tFlagsEnum = typeof(TFlagsEnum);
return (TFlagsEnum)Enum.ToObject(tFlagsEnum, ReadNamedBitListValue(expectedTag, tFlagsEnum));
}
/// <summary>
/// Reads the next value as a NamedBitList with tag UNIVERSAL 3, converting it to the
/// [<see cref="FlagsAttribute"/>] enum specfied by <paramref name="tFlagsEnum"/>.
/// </summary>
/// <param name="tFlagsEnum">Type object representing the destination type.</param>
/// <returns>
/// the NamedBitList value converted to a <paramref name="tFlagsEnum"/>.
/// </returns>
/// <exception cref="CryptographicException">
/// the next value does not have the correct tag --OR--
/// the length encoding is not valid under the current encoding rules --OR--
/// the contents are not valid under the current encoding rules --OR--
/// the encoded value is too big to fit in a <paramref name="tFlagsEnum"/> value
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="tFlagsEnum"/> is not an enum type --OR--
/// <paramref name="tFlagsEnum"/> was not declared with <see cref="FlagsAttribute"/>
/// </exception>
/// <seealso cref="ReadNamedBitListValue{TFlagsEnum}(Asn1Tag)"/>
public Enum ReadNamedBitListValue(Type tFlagsEnum) =>
ReadNamedBitListValue(Asn1Tag.PrimitiveBitString, tFlagsEnum);
/// <summary>
/// Reads the next value as a NamedBitList with tag UNIVERSAL 3, converting it to the
/// [<see cref="FlagsAttribute"/>] enum specfied by <paramref name="tFlagsEnum"/>.
/// </summary>
/// <param name="expectedTag">The tag to check for before reading.</param>
/// <param name="tFlagsEnum">Type object representing the destination type.</param>
/// <returns>
/// the NamedBitList value converted to a <paramref name="tFlagsEnum"/>.
/// </returns>
/// <exception cref="CryptographicException">
/// the next value does not have the correct tag --OR--
/// the length encoding is not valid under the current encoding rules --OR--
/// the contents are not valid under the current encoding rules --OR---
/// the encoded value is too big to fit in a <paramref name="tFlagsEnum"/> value
/// </exception>
/// <exception cref="ArgumentException">
/// <paramref name="tFlagsEnum"/> is not an enum type --OR--
/// <paramref name="tFlagsEnum"/> was not declared with <see cref="FlagsAttribute"/>
/// --OR--
/// <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagClass"/> is
/// <see cref="TagClass.Universal"/>, but
/// <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
/// the method
/// </exception>
/// <seealso cref="ReadNamedBitListValue{TFlagsEnum}(Asn1Tag)"/>
public Enum ReadNamedBitListValue(Asn1Tag expectedTag, Type tFlagsEnum)
{
AsnValueReader valueReader = OpenValueReader();
Enum ret = valueReader.ReadNamedBitListValue(expectedTag, tFlagsEnum);
valueReader.MatchSlice(ref _data);
return ret;
}
}
}
......@@ -4,7 +4,7 @@
namespace System.Security.Cryptography.Asn1
{
internal partial class AsnReader
internal ref partial struct AsnValueReader
{
/// <summary>
/// Reads the next value as a NULL with tag UNIVERSAL 5.
......@@ -46,4 +46,39 @@ public void ReadNull(Asn1Tag expectedTag)
_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);
}
}
}
......@@ -11,7 +11,7 @@
#nullable enable
namespace System.Security.Cryptography.Asn1
{
internal partial class AsnReader
internal ref partial struct AsnValueReader
{
/// <summary>
/// Reads the next value as an OBJECT IDENTIFIER with tag UNIVERSAL 6, returning
......@@ -218,8 +218,7 @@ private string ReadObjectIdentifierAsString(Asn1Tag expectedTag, out int totalBy
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding);
}
ReadOnlyMemory<byte> contentsMemory = Slice(_data, headerLength, length!.Value);
ReadOnlySpan<byte> contents = contentsMemory.Span;
ReadOnlySpan<byte> contents = Slice(_data, headerLength, length!.Value);
// Each byte can contribute a 3 digit value and a '.' (e.g. "126."), but usually
// they convey one digit and a separator.
......@@ -311,4 +310,79 @@ private string ReadObjectIdentifierAsString(Asn1Tag expectedTag, out int totalBy
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;
}
}
}
......@@ -4,15 +4,15 @@
namespace System.Security.Cryptography.Asn1
{
internal partial class AsnReader
internal ref partial struct AsnValueReader
{
/// <summary>
/// Reads the next value as a SEQUENCE or SEQUENCE-OF with tag UNIVERSAL 16
/// and returns the result as an <see cref="AsnReader"/> positioned at the first
/// and returns the result as an <see cref="AsnValueReader"/> positioned at the first
/// value in the sequence (or with <see cref="HasData"/> == <c>false</c>).
/// </summary>
/// <returns>
/// an <see cref="AsnReader"/> positioned at the first
/// an <see cref="AsnValueReader"/> positioned at the first
/// value in the sequence (or with <see cref="HasData"/> == <c>false</c>).
/// </returns>
/// <remarks>
......@@ -25,16 +25,16 @@ internal partial class AsnReader
/// the contents are not valid under the current encoding rules
/// </exception>
/// <see cref="ReadSequence(Asn1Tag)"/>
public AsnReader ReadSequence() => ReadSequence(Asn1Tag.Sequence);
public AsnValueReader ReadSequence() => ReadSequence(Asn1Tag.Sequence);
/// <summary>
/// Reads the next value as a SEQUENCE or SEQUENCE-OF with the specified tag
/// and returns the result as an <see cref="AsnReader"/> positioned at the first
/// and returns the result as an <see cref="AsnValueReader"/> positioned at the first
/// value in the sequence (or with <see cref="HasData"/> == <c>false</c>).
/// </summary>
/// <param name="expectedTag">The tag to check for before reading.</param>
/// <returns>
/// an <see cref="AsnReader"/> positioned at the first
/// an <see cref="AsnValueReader"/> positioned at the first
/// value in the sequence (or with <see cref="HasData"/> == <c>false</c>).
/// </returns>
/// <remarks>
......@@ -52,7 +52,7 @@ internal partial class AsnReader
/// <paramref name="expectedTag"/>.<see cref="Asn1Tag.TagValue"/> is not correct for
/// the method
/// </exception>
public AsnReader ReadSequence(Asn1Tag expectedTag)
public AsnValueReader ReadSequence(Asn1Tag expectedTag)
{
Asn1Tag tag = ReadTagAndLength(out int? length, out int headerLength);
CheckExpectedTag(tag, expectedTag, UniversalTagNumber.Sequence);
......@@ -72,10 +72,71 @@ public AsnReader ReadSequence(Asn1Tag expectedTag)
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;
}
}
}
......@@ -8,9 +8,8 @@
#nullable enable
namespace System.Security.Cryptography.Asn1
{
internal partial class AsnReader
internal ref partial struct AsnValueReader
{
/// <summary>
/// Reads the next value as a UTCTime with tag UNIVERSAL 23.
/// </summary>
......@@ -31,7 +30,6 @@ internal partial class AsnReader
public DateTimeOffset ReadUtcTime(int twoDigitYearMax = 2049) =>
ReadUtcTime(Asn1Tag.UtcTime, twoDigitYearMax);
/// <summary>
/// Reads the next value as a UTCTime with a specified tag.
/// </summary>
......@@ -72,8 +70,15 @@ public DateTimeOffset ReadUtcTime(Asn1Tag expectedTag, int twoDigitYearMax = 204
// T-REC-X.690-201510 sec 11.8
byte[]? rented = null;
// The longest format is 17 bytes.
Span<byte> tmpSpace = stackalloc byte[17];
Span<byte> tmpSpace;
unsafe
{
// The longest format is 17 bytes.
const int StackBufSize = 17;
byte* stackBuf = stackalloc byte[StackBufSize];
tmpSpace = new Span<byte>(stackBuf, StackBufSize);
}
ReadOnlySpan<byte> contents = GetOctetStringContents(
expectedTag,
......@@ -224,4 +229,58 @@ private DateTimeOffset ParseUtcTime(ReadOnlySpan<byte> contentOctets, int twoDig
}
}
}
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;
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册