Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2562415
First set of key loaders to use value-type reading
vcsjones Mar 12, 2026
a2bcda3
Migrates DSA SPKI
vcsjones Mar 12, 2026
d4e4e01
Move parts of RSA public key loading to value loader
vcsjones Mar 12, 2026
f83e2e7
Fix encoding of unknown algorithms
vcsjones Mar 12, 2026
aafa60b
Move more RSA public key reading to value readers
vcsjones Mar 12, 2026
f932e37
Remove dead reader code
vcsjones Mar 12, 2026
203b608
Remove unused memory reader
vcsjones Mar 12, 2026
b965e1e
Remove now unused code
vcsjones Mar 12, 2026
7d84a90
Value struct support for PasswordBasedEncryption
vcsjones Mar 12, 2026
6e809d2
Spanify DSA key loader
vcsjones Mar 12, 2026
c8acec4
Spanify RSA key loaded
vcsjones Mar 12, 2026
f477580
Tweak some types for future reading
vcsjones Mar 12, 2026
2abb5cf
Value-ify ML-KEM PKCS#8 export
vcsjones Mar 13, 2026
37bdfdf
Move Choice tag validation to file-scoped Validate class
vcsjones Mar 13, 2026
d19b823
Value reader and writer for ML-DSA only
vcsjones Mar 13, 2026
5d6b550
Move ECC key helpers
vcsjones Mar 13, 2026
16af805
Remove unused memory-based readers
vcsjones Mar 13, 2026
45bd2eb
Keep torching old readers
vcsjones Mar 13, 2026
45a0315
Done! Maybe? Hopefully.
vcsjones Mar 13, 2026
4dd9d87
Get rid of PointerMemoryManager in Android RSA key loader
vcsjones Mar 13, 2026
86ae7fb
Fix BOM
vcsjones Mar 13, 2026
873e05f
Remove value builder since we didn't end up using it... yet
vcsjones Mar 13, 2026
959d34f
Convert several loaders to be ref only
vcsjones Mar 13, 2026
7459a29
Change ECPrivateKey and dependent types to ref-only
vcsjones Mar 13, 2026
08e38e8
Remove unused attributes
vcsjones Mar 13, 2026
dce0681
Add back validation for ref-struct only emitted types
vcsjones Mar 13, 2026
020110a
Actually do validation
vcsjones Mar 13, 2026
60ba8d8
Fix tests
vcsjones Mar 13, 2026
5b44256
Back to key reader
vcsjones Mar 13, 2026
d57e61c
Add whitespace in the generated C#
vcsjones Mar 13, 2026
06e2428
Put the BOM back.
vcsjones Mar 13, 2026
b2727b6
Fix missing HasParameter assignments, fix missing slice
vcsjones Mar 13, 2026
4823899
Change optional fields to avoid torn values
vcsjones Mar 13, 2026
9c25918
Apply suggestion from @vcsjones
vcsjones Mar 13, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,19 @@ internal static bool RepresentsNull(ReadOnlyMemory<byte>? parameters)

return span[1] == 0;
}

internal ValueAlgorithmIdentifierAsn AsValueAlgorithmIdentifierAsn()
{
ValueAlgorithmIdentifierAsn val = default;
val.Algorithm = Algorithm;

if (Parameters is ReadOnlyMemory<byte> parameters)
{
val.Parameters = parameters.Span;
}

return val;
}
}

internal ref partial struct ValueAlgorithmIdentifierAsn
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,52 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R
internal ref partial struct ValueAlgorithmIdentifierAsn
{
internal string Algorithm;
internal ReadOnlySpan<byte> Parameters;
internal bool HasParameters;

internal ReadOnlySpan<byte> Parameters
{
get;
set
{
HasParameters = true;
field = value;
}
}

internal bool HasParameters { get; private set; }

internal readonly void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}

internal readonly void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);

try
{
writer.WriteObjectIdentifier(Algorithm);
}
catch (ArgumentException e)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
}

if (HasParameters)
{

try
{
writer.WriteEncodedValue(Parameters);
}
catch (ArgumentException e)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
}
}

writer.PopSequence(tag);
}

internal static void Decode(ReadOnlySpan<byte> encoded, AsnEncodingRules ruleSet, out ValueAlgorithmIdentifierAsn decoded)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,35 @@ internal ref partial struct ValueAttributeAsn
internal string AttrType;
internal ReadOnlySpan<byte> AttrValues;

internal readonly void Encode(AsnWriter writer)
{
Encode(writer, Asn1Tag.Sequence);
}

internal readonly void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);

try
{
writer.WriteObjectIdentifier(AttrType);
}
catch (ArgumentException e)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
}

try
{
writer.WriteEncodedValue(AttrValues);
}
catch (ArgumentException e)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
}
writer.PopSequence(tag);
}

internal static void Decode(ReadOnlySpan<byte> encoded, AsnEncodingRules ruleSet, out ValueAttributeAsn decoded)
{
Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
<asn:Sequence
xmlns:asn="http://schemas.dot.net/asnxml/201808/"
name="CurveAsn"
namespace="System.Security.Cryptography.Asn1">
namespace="System.Security.Cryptography.Asn1"
emitType="ref">

<!--
https://www.secg.org/sec1-v2.pdf, C.2
Expand All @@ -20,4 +21,4 @@
<asn:OctetString name="A" />
<asn:OctetString name="B" />
<asn:BitString name="Seed" optional="true" />
</asn:Sequence>
</asn:Sequence>
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,22 @@
namespace System.Security.Cryptography.Asn1
{
[StructLayout(LayoutKind.Sequential)]
internal partial struct CurveAsn
internal ref partial struct ValueCurveAsn
{
internal ReadOnlyMemory<byte> A;
internal ReadOnlyMemory<byte> B;
internal ReadOnlyMemory<byte>? Seed;
internal ReadOnlySpan<byte> A;
internal ReadOnlySpan<byte> B;

internal ReadOnlySpan<byte> Seed
{
get;
set
{
HasSeed = true;
field = value;
}
}

internal bool HasSeed { get; private set; }

internal readonly void Encode(AsnWriter writer)
{
Expand All @@ -24,67 +35,64 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag)
{
writer.PushSequence(tag);

writer.WriteOctetString(A.Span);
writer.WriteOctetString(B.Span);
writer.WriteOctetString(A);
writer.WriteOctetString(B);

if (Seed.HasValue)
if (HasSeed)
{
writer.WriteBitString(Seed.Value.Span, 0);
writer.WriteBitString(Seed, 0);
}

writer.PopSequence(tag);
}

internal static CurveAsn Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
internal static void Decode(ReadOnlySpan<byte> encoded, AsnEncodingRules ruleSet, out ValueCurveAsn decoded)
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded);
}

internal static CurveAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan<byte> encoded, AsnEncodingRules ruleSet, out ValueCurveAsn decoded)
{
try
{
ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet);
ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet);

DecodeCore(ref reader, expectedTag, encoded, out CurveAsn decoded);
DecodeCore(ref reader, expectedTag, out decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
catch (AsnContentException e)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
}
}

internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory<byte> rebind, out CurveAsn decoded)
internal static void Decode(scoped ref ValueAsnReader reader, out ValueCurveAsn decoded)
{
Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded);
Decode(ref reader, Asn1Tag.Sequence, out decoded);
}

internal static void Decode(ref ValueAsnReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out CurveAsn decoded)
internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueCurveAsn decoded)
{
try
{
DecodeCore(ref reader, expectedTag, rebind, out decoded);
DecodeCore(ref reader, expectedTag, out decoded);
}
catch (AsnContentException e)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
}
}

private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, ReadOnlyMemory<byte> rebind, out CurveAsn decoded)
private static void DecodeCore(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueCurveAsn decoded)
{
decoded = default;
ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag);
ReadOnlySpan<byte> rebindSpan = rebind.Span;
int offset;
ReadOnlySpan<byte> tmpSpan;


if (sequenceReader.TryReadPrimitiveOctetString(out tmpSpan))
{
decoded.A = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
decoded.A = tmpSpan;
}
else
{
Expand All @@ -94,7 +102,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R

if (sequenceReader.TryReadPrimitiveOctetString(out tmpSpan))
{
decoded.B = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
decoded.B = tmpSpan;
}
else
{
Expand All @@ -107,13 +115,14 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R

if (sequenceReader.TryReadPrimitiveBitString(out _, out tmpSpan))
{
decoded.Seed = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray();
decoded.Seed = tmpSpan;
}
else
{
decoded.Seed = sequenceReader.ReadBitString(out _);
}

decoded.HasSeed = true;
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,10 @@

namespace System.Security.Cryptography.Asn1
{
[StructLayout(LayoutKind.Sequential)]
internal partial struct DirectoryStringAsn
{
internal string? TeletexString;
internal string? PrintableString;
internal ReadOnlyMemory<byte>? UniversalString;
internal string? Utf8String;
internal string? BmpString;

#if DEBUG
static DirectoryStringAsn()
file static class ValidateDirectoryStringAsn
{
static ValidateDirectoryStringAsn()
{
var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>();
Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) =>
Expand All @@ -37,6 +30,28 @@ static DirectoryStringAsn()
ensureUniqueTag(new Asn1Tag(UniversalTagNumber.UTF8String), "Utf8String");
ensureUniqueTag(new Asn1Tag(UniversalTagNumber.BMPString), "BmpString");
}

[System.Runtime.CompilerServices.MethodImpl(
System.Runtime.CompilerServices.MethodImplOptions.NoInlining |
System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)]
internal static void Validate() { }
}
#endif

[StructLayout(LayoutKind.Sequential)]
internal partial struct DirectoryStringAsn
{
internal string? TeletexString;
internal string? PrintableString;
internal ReadOnlyMemory<byte>? UniversalString;
internal string? Utf8String;
internal string? BmpString;

#if DEBUG
static DirectoryStringAsn()
{
ValidateDirectoryStringAsn.Validate();
}
#endif

internal readonly void Encode(AsnWriter writer)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
xmlns:asn="http://schemas.dot.net/asnxml/201808/"
name="DssParms"
namespace="System.Security.Cryptography.Asn1"
rebind="false">
emitType="ref">

<!--
https://tools.ietf.org/html/rfc3279#section-2.3.2
Expand All @@ -17,4 +17,4 @@
<asn:Integer name="P" />
<asn:Integer name="Q" />
<asn:Integer name="G" />
</asn:Sequence>
</asn:Sequence>
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
namespace System.Security.Cryptography.Asn1
{
[StructLayout(LayoutKind.Sequential)]
internal partial struct DssParms
internal ref partial struct ValueDssParms
{
internal System.Numerics.BigInteger P;
internal System.Numerics.BigInteger Q;
Expand All @@ -30,33 +30,32 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag)
writer.PopSequence(tag);
}

internal static DssParms Decode(ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
internal static void Decode(ReadOnlySpan<byte> encoded, AsnEncodingRules ruleSet, out ValueDssParms decoded)
{
return Decode(Asn1Tag.Sequence, encoded, ruleSet);
Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded);
}

internal static DssParms Decode(Asn1Tag expectedTag, ReadOnlyMemory<byte> encoded, AsnEncodingRules ruleSet)
internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan<byte> encoded, AsnEncodingRules ruleSet, out ValueDssParms decoded)
{
try
{
ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet);
ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet);

DecodeCore(ref reader, expectedTag, out DssParms decoded);
DecodeCore(ref reader, expectedTag, out decoded);
reader.ThrowIfNotEmpty();
return decoded;
}
catch (AsnContentException e)
{
throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e);
}
}

internal static void Decode(ref ValueAsnReader reader, out DssParms decoded)
internal static void Decode(scoped ref ValueAsnReader reader, out ValueDssParms decoded)
{
Decode(ref reader, Asn1Tag.Sequence, out decoded);
}

internal static void Decode(ref ValueAsnReader reader, Asn1Tag expectedTag, out DssParms decoded)
internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueDssParms decoded)
{
try
{
Expand All @@ -68,7 +67,7 @@ internal static void Decode(ref ValueAsnReader reader, Asn1Tag expectedTag, out
}
}

private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, out DssParms decoded)
private static void DecodeCore(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueDssParms decoded)
{
decoded = default;
ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag);
Expand Down
Loading
Loading