diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.manual.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.manual.cs index b8a5da88b67b47..6fbcc3fdeaba1a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.manual.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.manual.cs @@ -58,6 +58,19 @@ internal static bool RepresentsNull(ReadOnlyMemory? parameters) return span[1] == 0; } + + internal ValueAlgorithmIdentifierAsn AsValueAlgorithmIdentifierAsn() + { + ValueAlgorithmIdentifierAsn val = default; + val.Algorithm = Algorithm; + + if (Parameters is ReadOnlyMemory parameters) + { + val.Parameters = parameters.Span; + } + + return val; + } } internal ref partial struct ValueAlgorithmIdentifierAsn diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml.cs index f9b8eae0bdf29d..b016191ccadf5b 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml.cs @@ -110,8 +110,52 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R internal ref partial struct ValueAlgorithmIdentifierAsn { internal string Algorithm; - internal ReadOnlySpan Parameters; - internal bool HasParameters; + + internal ReadOnlySpan 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 encoded, AsnEncodingRules ruleSet, out ValueAlgorithmIdentifierAsn decoded) { diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.xml.cs index a25b39a22327c6..947f33222f3d73 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.xml.cs @@ -126,6 +126,35 @@ internal ref partial struct ValueAttributeAsn internal string AttrType; internal ReadOnlySpan 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 encoded, AsnEncodingRules ruleSet, out ValueAttributeAsn decoded) { Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/CurveAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/CurveAsn.xml index 9c02e2713b5e3e..ab98def6b4b38a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/CurveAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/CurveAsn.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="ref"> - + - \ No newline at end of file + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECDomainParameters.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECDomainParameters.xml.cs index c5c1a5cd340afc..a767b35b44bcfc 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECDomainParameters.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECDomainParameters.xml.cs @@ -8,14 +8,10 @@ namespace System.Security.Cryptography.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct ECDomainParameters - { - internal System.Security.Cryptography.Asn1.SpecifiedECDomain? Specified; - internal string? Named; - #if DEBUG - static ECDomainParameters() + file static class ValidateECDomainParameters + { + static ValidateECDomainParameters() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -31,18 +27,48 @@ static ECDomainParameters() ensureUniqueTag(Asn1Tag.Sequence, "Specified"); ensureUniqueTag(Asn1Tag.ObjectIdentifier, "Named"); } + + [System.Runtime.CompilerServices.MethodImpl( + System.Runtime.CompilerServices.MethodImplOptions.NoInlining | + System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)] + internal static void Validate() { } + } +#endif + + [StructLayout(LayoutKind.Sequential)] + internal ref partial struct ValueECDomainParameters + { + + internal System.Security.Cryptography.Asn1.ValueSpecifiedECDomain Specified + { + get; + set + { + HasSpecified = true; + field = value; + } + } + + internal bool HasSpecified { get; private set; } + internal string? Named; + +#if DEBUG + static ValueECDomainParameters() + { + ValidateECDomainParameters.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) { bool wroteValue = false; - if (Specified.HasValue) + if (HasSpecified) { if (wroteValue) throw new CryptographicException(); - Specified.Value.Encode(writer); + Specified.Encode(writer); wroteValue = true; } @@ -68,15 +94,14 @@ internal readonly void Encode(AsnWriter writer) } } - internal static ECDomainParameters Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueECDomainParameters decoded) { try { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); - DecodeCore(ref reader, encoded, out ECDomainParameters decoded); + DecodeCore(ref reader, out decoded); reader.ThrowIfNotEmpty(); - return decoded; } catch (AsnContentException e) { @@ -84,11 +109,11 @@ internal static ECDomainParameters Decode(ReadOnlyMemory encoded, AsnEncod } } - internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebind, out ECDomainParameters decoded) + internal static void Decode(scoped ref ValueAsnReader reader, out ValueECDomainParameters decoded) { try { - DecodeCore(ref reader, rebind, out decoded); + DecodeCore(ref reader, out decoded); } catch (AsnContentException e) { @@ -96,17 +121,18 @@ internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebi } } - private static void DecodeCore(ref ValueAsnReader reader, ReadOnlyMemory rebind, out ECDomainParameters decoded) + private static void DecodeCore(scoped ref ValueAsnReader reader, out ValueECDomainParameters decoded) { decoded = default; Asn1Tag tag = reader.PeekTag(); if (tag.HasSameClassAndValue(Asn1Tag.Sequence)) { - System.Security.Cryptography.Asn1.SpecifiedECDomain tmpSpecified; - System.Security.Cryptography.Asn1.SpecifiedECDomain.Decode(ref reader, rebind, out tmpSpecified); + System.Security.Cryptography.Asn1.ValueSpecifiedECDomain tmpSpecified; + System.Security.Cryptography.Asn1.ValueSpecifiedECDomain.Decode(ref reader, out tmpSpecified); decoded.Specified = tmpSpecified; + decoded.HasSpecified = true; } else if (tag.HasSameClassAndValue(Asn1Tag.ObjectIdentifier)) { diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml index c5fcf187449e23..d7d087cc50254f 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="ref"> - + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml.cs index 5b1bd3e8efd494..dc8385227eb5d1 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/ECPrivateKey.xml.cs @@ -9,12 +9,34 @@ namespace System.Security.Cryptography.Asn1 { [StructLayout(LayoutKind.Sequential)] - internal partial struct ECPrivateKey + internal ref partial struct ValueECPrivateKey { internal int Version; - internal ReadOnlyMemory PrivateKey; - internal System.Security.Cryptography.Asn1.ECDomainParameters? Parameters; - internal ReadOnlyMemory? PublicKey; + internal ReadOnlySpan PrivateKey; + + internal System.Security.Cryptography.Asn1.ValueECDomainParameters Parameters + { + get; + set + { + HasParameters = true; + field = value; + } + } + + internal bool HasParameters { get; private set; } + + internal ReadOnlySpan PublicKey + { + get; + set + { + HasPublicKey = true; + field = value; + } + } + + internal bool HasPublicKey { get; private set; } internal readonly void Encode(AsnWriter writer) { @@ -26,40 +48,39 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) writer.PushSequence(tag); writer.WriteInteger(Version); - writer.WriteOctetString(PrivateKey.Span); + writer.WriteOctetString(PrivateKey); - if (Parameters.HasValue) + if (HasParameters) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); - Parameters.Value.Encode(writer); + Parameters.Encode(writer); writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); } - if (PublicKey.HasValue) + if (HasPublicKey) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); - writer.WriteBitString(PublicKey.Value.Span, 0); + writer.WriteBitString(PublicKey, 0); writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); } writer.PopSequence(tag); } - internal static ECPrivateKey Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueECPrivateKey decoded) { - return Decode(Asn1Tag.Sequence, encoded, ruleSet); + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); } - internal static ECPrivateKey Decode(Asn1Tag expectedTag, ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueECPrivateKey decoded) { try { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); - DecodeCore(ref reader, expectedTag, encoded, out ECPrivateKey decoded); + DecodeCore(ref reader, expectedTag, out decoded); reader.ThrowIfNotEmpty(); - return decoded; } catch (AsnContentException e) { @@ -67,16 +88,16 @@ internal static ECPrivateKey Decode(Asn1Tag expectedTag, ReadOnlyMemory en } } - internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebind, out ECPrivateKey decoded) + internal static void Decode(scoped ref ValueAsnReader reader, out ValueECPrivateKey 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 rebind, out ECPrivateKey decoded) + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueECPrivateKey decoded) { try { - DecodeCore(ref reader, expectedTag, rebind, out decoded); + DecodeCore(ref reader, expectedTag, out decoded); } catch (AsnContentException e) { @@ -84,13 +105,11 @@ internal static void Decode(ref ValueAsnReader reader, Asn1Tag expectedTag, Read } } - private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out ECPrivateKey decoded) + private static void DecodeCore(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueECPrivateKey decoded) { decoded = default; ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); ValueAsnReader explicitReader; - ReadOnlySpan rebindSpan = rebind.Span; - int offset; ReadOnlySpan tmpSpan; @@ -102,7 +121,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R if (sequenceReader.TryReadPrimitiveOctetString(out tmpSpan)) { - decoded.PrivateKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.PrivateKey = tmpSpan; } else { @@ -113,10 +132,11 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0))) { explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); - System.Security.Cryptography.Asn1.ECDomainParameters tmpParameters; - System.Security.Cryptography.Asn1.ECDomainParameters.Decode(ref explicitReader, rebind, out tmpParameters); + System.Security.Cryptography.Asn1.ValueECDomainParameters tmpParameters; + System.Security.Cryptography.Asn1.ValueECDomainParameters.Decode(ref explicitReader, out tmpParameters); decoded.Parameters = tmpParameters; + decoded.HasParameters = true; explicitReader.ThrowIfNotEmpty(); } @@ -127,13 +147,14 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R if (explicitReader.TryReadPrimitiveBitString(out _, out tmpSpan)) { - decoded.PublicKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.PublicKey = tmpSpan; } else { decoded.PublicKey = explicitReader.ReadBitString(out _); } + decoded.HasPublicKey = true; explicitReader.ThrowIfNotEmpty(); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml index e15636e8171d52..d3d4ced0f53ed4 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="both"> - + - \ No newline at end of file + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml.cs index 6c934f9d2f9520..ea916323870e1a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/EncryptedPrivateKeyInfoAsn.xml.cs @@ -86,6 +86,85 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } + sequenceReader.ThrowIfNotEmpty(); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal ref partial struct ValueEncryptedPrivateKeyInfoAsn + { + internal System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn EncryptionAlgorithm; + internal ReadOnlySpan EncryptedData; + + internal readonly void Encode(AsnWriter writer) + { + Encode(writer, Asn1Tag.Sequence); + } + + internal readonly void Encode(AsnWriter writer, Asn1Tag tag) + { + writer.PushSequence(tag); + + EncryptionAlgorithm.Encode(writer); + writer.WriteOctetString(EncryptedData); + writer.PopSequence(tag); + } + + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueEncryptedPrivateKeyInfoAsn decoded) + { + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); + } + + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueEncryptedPrivateKeyInfoAsn decoded) + { + try + { + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); + + DecodeCore(ref reader, expectedTag, out decoded); + reader.ThrowIfNotEmpty(); + } + catch (AsnContentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + } + + internal static void Decode(scoped ref ValueAsnReader reader, out ValueEncryptedPrivateKeyInfoAsn decoded) + { + Decode(ref reader, Asn1Tag.Sequence, out decoded); + } + + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueEncryptedPrivateKeyInfoAsn decoded) + { + try + { + DecodeCore(ref reader, expectedTag, out decoded); + } + catch (AsnContentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + } + + private static void DecodeCore(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueEncryptedPrivateKeyInfoAsn decoded) + { + decoded = default; + ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); + ReadOnlySpan tmpSpan; + + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref sequenceReader, out decoded.EncryptionAlgorithm); + + if (sequenceReader.TryReadPrimitiveOctetString(out tmpSpan)) + { + decoded.EncryptedData = tmpSpan; + } + else + { + decoded.EncryptedData = sequenceReader.ReadOctetString(); + } + + sequenceReader.ThrowIfNotEmpty(); } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml index f57c184dcacc93..a4603981ca47dc 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="ref"> - \ No newline at end of file + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml.cs index d60d6723b68891..e8b44b15ec5b1b 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/FieldID.xml.cs @@ -9,10 +9,10 @@ namespace System.Security.Cryptography.Asn1 { [StructLayout(LayoutKind.Sequential)] - internal partial struct FieldID + internal ref partial struct ValueFieldID { internal string FieldType; - internal ReadOnlyMemory Parameters; + internal ReadOnlySpan Parameters; internal readonly void Encode(AsnWriter writer) { @@ -31,9 +31,10 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } + try { - writer.WriteEncodedValue(Parameters.Span); + writer.WriteEncodedValue(Parameters); } catch (ArgumentException e) { @@ -42,20 +43,19 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) writer.PopSequence(tag); } - internal static FieldID Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueFieldID decoded) { - return Decode(Asn1Tag.Sequence, encoded, ruleSet); + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); } - internal static FieldID Decode(Asn1Tag expectedTag, ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueFieldID decoded) { try { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); - DecodeCore(ref reader, expectedTag, encoded, out FieldID decoded); + DecodeCore(ref reader, expectedTag, out decoded); reader.ThrowIfNotEmpty(); - return decoded; } catch (AsnContentException e) { @@ -63,16 +63,16 @@ internal static FieldID Decode(Asn1Tag expectedTag, ReadOnlyMemory encoded } } - internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebind, out FieldID decoded) + internal static void Decode(scoped ref ValueAsnReader reader, out ValueFieldID 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 rebind, out FieldID decoded) + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueFieldID decoded) { try { - DecodeCore(ref reader, expectedTag, rebind, out decoded); + DecodeCore(ref reader, expectedTag, out decoded); } catch (AsnContentException e) { @@ -80,17 +80,13 @@ internal static void Decode(ref ValueAsnReader reader, Asn1Tag expectedTag, Read } } - private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out FieldID decoded) + private static void DecodeCore(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueFieldID decoded) { decoded = default; ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); - ReadOnlySpan rebindSpan = rebind.Span; - int offset; - ReadOnlySpan tmpSpan; decoded.FieldType = sequenceReader.ReadObjectIdentifier(); - tmpSpan = sequenceReader.ReadEncodedValue(); - decoded.Parameters = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.Parameters = sequenceReader.ReadEncodedValue(); sequenceReader.ThrowIfNotEmpty(); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/GeneralNameAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/GeneralNameAsn.xml.cs index 022813b3f73c04..a39128815529ac 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/GeneralNameAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/GeneralNameAsn.xml.cs @@ -8,21 +8,10 @@ namespace System.Security.Cryptography.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct GeneralNameAsn - { - internal System.Security.Cryptography.Asn1.OtherNameAsn? OtherName; - internal string? Rfc822Name; - internal string? DnsName; - internal ReadOnlyMemory? X400Address; - internal ReadOnlyMemory? DirectoryName; - internal System.Security.Cryptography.Asn1.EdiPartyNameAsn? EdiPartyName; - internal string? Uri; - internal ReadOnlyMemory? IPAddress; - internal string? RegisteredId; - #if DEBUG - static GeneralNameAsn() + file static class ValidateGeneralNameAsn + { + static ValidateGeneralNameAsn() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -45,6 +34,32 @@ static GeneralNameAsn() ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 7), "IPAddress"); ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 8), "RegisteredId"); } + + [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 GeneralNameAsn + { + internal System.Security.Cryptography.Asn1.OtherNameAsn? OtherName; + internal string? Rfc822Name; + internal string? DnsName; + internal ReadOnlyMemory? X400Address; + internal ReadOnlyMemory? DirectoryName; + internal System.Security.Cryptography.Asn1.EdiPartyNameAsn? EdiPartyName; + internal string? Uri; + internal ReadOnlyMemory? IPAddress; + internal string? RegisteredId; + +#if DEBUG + static GeneralNameAsn() + { + ValidateGeneralNameAsn.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/GeneralSubtreeAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/GeneralSubtreeAsn.xml.cs index c8f2f2a4036c9c..a676abf4959b0c 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/GeneralSubtreeAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/GeneralSubtreeAsn.xml.cs @@ -1,4 +1,4 @@ -// Licensed to the .NET Foundation under one or more agreements. +// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. #pragma warning disable SA1028 // ignore whitespace warnings for generated code diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLDsaPrivateKeyAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLDsaPrivateKeyAsn.xml index 439609c36fc65f..d612dfa842722e 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLDsaPrivateKeyAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLDsaPrivateKeyAsn.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="ref"> - + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLDsaPrivateKeyAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLDsaPrivateKeyAsn.xml.cs index af874c8186eb70..1c1d204457d223 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLDsaPrivateKeyAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLDsaPrivateKeyAsn.xml.cs @@ -8,15 +8,10 @@ namespace System.Security.Cryptography.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct MLDsaPrivateKeyAsn - { - internal ReadOnlyMemory? Seed; - internal ReadOnlyMemory? ExpandedKey; - internal System.Security.Cryptography.Asn1.MLDsaPrivateKeyBothAsn? Both; - #if DEBUG - static MLDsaPrivateKeyAsn() + file static class ValidateMLDsaPrivateKeyAsn + { + static ValidateMLDsaPrivateKeyAsn() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -33,36 +28,89 @@ static MLDsaPrivateKeyAsn() ensureUniqueTag(Asn1Tag.PrimitiveOctetString, "ExpandedKey"); ensureUniqueTag(Asn1Tag.Sequence, "Both"); } + + [System.Runtime.CompilerServices.MethodImpl( + System.Runtime.CompilerServices.MethodImplOptions.NoInlining | + System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)] + internal static void Validate() { } + } +#endif + + [StructLayout(LayoutKind.Sequential)] + internal ref partial struct ValueMLDsaPrivateKeyAsn + { + + internal ReadOnlySpan Seed + { + get; + set + { + HasSeed = true; + field = value; + } + } + + internal bool HasSeed { get; private set; } + + internal ReadOnlySpan ExpandedKey + { + get; + set + { + HasExpandedKey = true; + field = value; + } + } + + internal bool HasExpandedKey { get; private set; } + + internal System.Security.Cryptography.Asn1.ValueMLDsaPrivateKeyBothAsn Both + { + get; + set + { + HasBoth = true; + field = value; + } + } + + internal bool HasBoth { get; private set; } + +#if DEBUG + static ValueMLDsaPrivateKeyAsn() + { + ValidateMLDsaPrivateKeyAsn.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) { bool wroteValue = false; - if (Seed.HasValue) + if (HasSeed) { if (wroteValue) throw new CryptographicException(); - writer.WriteOctetString(Seed.Value.Span, new Asn1Tag(TagClass.ContextSpecific, 0)); + writer.WriteOctetString(Seed, new Asn1Tag(TagClass.ContextSpecific, 0)); wroteValue = true; } - if (ExpandedKey.HasValue) + if (HasExpandedKey) { if (wroteValue) throw new CryptographicException(); - writer.WriteOctetString(ExpandedKey.Value.Span); + writer.WriteOctetString(ExpandedKey); wroteValue = true; } - if (Both.HasValue) + if (HasBoth) { if (wroteValue) throw new CryptographicException(); - Both.Value.Encode(writer); + Both.Encode(writer); wroteValue = true; } @@ -72,15 +120,14 @@ internal readonly void Encode(AsnWriter writer) } } - internal static MLDsaPrivateKeyAsn Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueMLDsaPrivateKeyAsn decoded) { try { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); - DecodeCore(ref reader, encoded, out MLDsaPrivateKeyAsn decoded); + DecodeCore(ref reader, out decoded); reader.ThrowIfNotEmpty(); - return decoded; } catch (AsnContentException e) { @@ -88,11 +135,11 @@ internal static MLDsaPrivateKeyAsn Decode(ReadOnlyMemory encoded, AsnEncod } } - internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebind, out MLDsaPrivateKeyAsn decoded) + internal static void Decode(scoped ref ValueAsnReader reader, out ValueMLDsaPrivateKeyAsn decoded) { try { - DecodeCore(ref reader, rebind, out decoded); + DecodeCore(ref reader, out decoded); } catch (AsnContentException e) { @@ -100,12 +147,10 @@ internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebi } } - private static void DecodeCore(ref ValueAsnReader reader, ReadOnlyMemory rebind, out MLDsaPrivateKeyAsn decoded) + private static void DecodeCore(scoped ref ValueAsnReader reader, out ValueMLDsaPrivateKeyAsn decoded) { decoded = default; Asn1Tag tag = reader.PeekTag(); - ReadOnlySpan rebindSpan = rebind.Span; - int offset; ReadOnlySpan tmpSpan; if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0))) @@ -113,33 +158,36 @@ private static void DecodeCore(ref ValueAsnReader reader, ReadOnlyMemory r if (reader.TryReadPrimitiveOctetString(out tmpSpan, new Asn1Tag(TagClass.ContextSpecific, 0))) { - decoded.Seed = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.Seed = tmpSpan; } else { decoded.Seed = reader.ReadOctetString(new Asn1Tag(TagClass.ContextSpecific, 0)); } + decoded.HasSeed = true; } else if (tag.HasSameClassAndValue(Asn1Tag.PrimitiveOctetString)) { if (reader.TryReadPrimitiveOctetString(out tmpSpan)) { - decoded.ExpandedKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.ExpandedKey = tmpSpan; } else { decoded.ExpandedKey = reader.ReadOctetString(); } + decoded.HasExpandedKey = true; } else if (tag.HasSameClassAndValue(Asn1Tag.Sequence)) { - System.Security.Cryptography.Asn1.MLDsaPrivateKeyBothAsn tmpBoth; - System.Security.Cryptography.Asn1.MLDsaPrivateKeyBothAsn.Decode(ref reader, rebind, out tmpBoth); + System.Security.Cryptography.Asn1.ValueMLDsaPrivateKeyBothAsn tmpBoth; + System.Security.Cryptography.Asn1.ValueMLDsaPrivateKeyBothAsn.Decode(ref reader, out tmpBoth); decoded.Both = tmpBoth; + decoded.HasBoth = true; } else { diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLDsaPrivateKeyBothAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLDsaPrivateKeyBothAsn.xml index 8f19fe890289f7..9aef0fc9dc39fc 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLDsaPrivateKeyBothAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLDsaPrivateKeyBothAsn.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="ref"> - + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLKemPrivateKeyAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLKemPrivateKeyAsn.xml.cs index 7b15373d0afa72..cd2ab689a2d953 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLKemPrivateKeyAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLKemPrivateKeyAsn.xml.cs @@ -8,15 +8,10 @@ namespace System.Security.Cryptography.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct MLKemPrivateKeyAsn - { - internal ReadOnlyMemory? Seed; - internal ReadOnlyMemory? ExpandedKey; - internal System.Security.Cryptography.Asn1.MLKemPrivateKeyBothAsn? Both; - #if DEBUG - static MLKemPrivateKeyAsn() + file static class ValidateMLKemPrivateKeyAsn + { + static ValidateMLKemPrivateKeyAsn() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -33,36 +28,89 @@ static MLKemPrivateKeyAsn() ensureUniqueTag(Asn1Tag.PrimitiveOctetString, "ExpandedKey"); ensureUniqueTag(Asn1Tag.Sequence, "Both"); } + + [System.Runtime.CompilerServices.MethodImpl( + System.Runtime.CompilerServices.MethodImplOptions.NoInlining | + System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)] + internal static void Validate() { } + } +#endif + + [StructLayout(LayoutKind.Sequential)] + internal ref partial struct ValueMLKemPrivateKeyAsn + { + + internal ReadOnlySpan Seed + { + get; + set + { + HasSeed = true; + field = value; + } + } + + internal bool HasSeed { get; private set; } + + internal ReadOnlySpan ExpandedKey + { + get; + set + { + HasExpandedKey = true; + field = value; + } + } + + internal bool HasExpandedKey { get; private set; } + + internal System.Security.Cryptography.Asn1.ValueMLKemPrivateKeyBothAsn Both + { + get; + set + { + HasBoth = true; + field = value; + } + } + + internal bool HasBoth { get; private set; } + +#if DEBUG + static ValueMLKemPrivateKeyAsn() + { + ValidateMLKemPrivateKeyAsn.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) { bool wroteValue = false; - if (Seed.HasValue) + if (HasSeed) { if (wroteValue) throw new CryptographicException(); - writer.WriteOctetString(Seed.Value.Span, new Asn1Tag(TagClass.ContextSpecific, 0)); + writer.WriteOctetString(Seed, new Asn1Tag(TagClass.ContextSpecific, 0)); wroteValue = true; } - if (ExpandedKey.HasValue) + if (HasExpandedKey) { if (wroteValue) throw new CryptographicException(); - writer.WriteOctetString(ExpandedKey.Value.Span); + writer.WriteOctetString(ExpandedKey); wroteValue = true; } - if (Both.HasValue) + if (HasBoth) { if (wroteValue) throw new CryptographicException(); - Both.Value.Encode(writer); + Both.Encode(writer); wroteValue = true; } @@ -72,15 +120,14 @@ internal readonly void Encode(AsnWriter writer) } } - internal static MLKemPrivateKeyAsn Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueMLKemPrivateKeyAsn decoded) { try { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); - DecodeCore(ref reader, encoded, out MLKemPrivateKeyAsn decoded); + DecodeCore(ref reader, out decoded); reader.ThrowIfNotEmpty(); - return decoded; } catch (AsnContentException e) { @@ -88,11 +135,11 @@ internal static MLKemPrivateKeyAsn Decode(ReadOnlyMemory encoded, AsnEncod } } - internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebind, out MLKemPrivateKeyAsn decoded) + internal static void Decode(scoped ref ValueAsnReader reader, out ValueMLKemPrivateKeyAsn decoded) { try { - DecodeCore(ref reader, rebind, out decoded); + DecodeCore(ref reader, out decoded); } catch (AsnContentException e) { @@ -100,12 +147,10 @@ internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebi } } - private static void DecodeCore(ref ValueAsnReader reader, ReadOnlyMemory rebind, out MLKemPrivateKeyAsn decoded) + private static void DecodeCore(scoped ref ValueAsnReader reader, out ValueMLKemPrivateKeyAsn decoded) { decoded = default; Asn1Tag tag = reader.PeekTag(); - ReadOnlySpan rebindSpan = rebind.Span; - int offset; ReadOnlySpan tmpSpan; if (tag.HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0))) @@ -113,33 +158,36 @@ private static void DecodeCore(ref ValueAsnReader reader, ReadOnlyMemory r if (reader.TryReadPrimitiveOctetString(out tmpSpan, new Asn1Tag(TagClass.ContextSpecific, 0))) { - decoded.Seed = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.Seed = tmpSpan; } else { decoded.Seed = reader.ReadOctetString(new Asn1Tag(TagClass.ContextSpecific, 0)); } + decoded.HasSeed = true; } else if (tag.HasSameClassAndValue(Asn1Tag.PrimitiveOctetString)) { if (reader.TryReadPrimitiveOctetString(out tmpSpan)) { - decoded.ExpandedKey = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.ExpandedKey = tmpSpan; } else { decoded.ExpandedKey = reader.ReadOctetString(); } + decoded.HasExpandedKey = true; } else if (tag.HasSameClassAndValue(Asn1Tag.Sequence)) { - System.Security.Cryptography.Asn1.MLKemPrivateKeyBothAsn tmpBoth; - System.Security.Cryptography.Asn1.MLKemPrivateKeyBothAsn.Decode(ref reader, rebind, out tmpBoth); + System.Security.Cryptography.Asn1.ValueMLKemPrivateKeyBothAsn tmpBoth; + System.Security.Cryptography.Asn1.ValueMLKemPrivateKeyBothAsn.Decode(ref reader, out tmpBoth); decoded.Both = tmpBoth; + decoded.HasBoth = true; } else { diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLKemPrivateKeyBothAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLKemPrivateKeyBothAsn.xml index 9360d3255dc22f..dfc530977a3817 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLKemPrivateKeyBothAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/MLKemPrivateKeyBothAsn.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="ref"> @@ -21,4 +22,4 @@ that specific platforms may have their own limits. This defines ours to int.MaxValue. --> - \ No newline at end of file + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.xml.cs index efe53f8cf4e780..5a3e34508257e1 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBEParameter.xml.cs @@ -9,9 +9,9 @@ namespace System.Security.Cryptography.Asn1 { [StructLayout(LayoutKind.Sequential)] - internal partial struct PBEParameter + internal ref partial struct ValuePBEParameter { - internal ReadOnlyMemory Salt; + internal ReadOnlySpan Salt; internal int IterationCount; internal readonly void Encode(AsnWriter writer) @@ -23,25 +23,24 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) { writer.PushSequence(tag); - writer.WriteOctetString(Salt.Span); + writer.WriteOctetString(Salt); writer.WriteInteger(IterationCount); writer.PopSequence(tag); } - internal static PBEParameter Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValuePBEParameter decoded) { - return Decode(Asn1Tag.Sequence, encoded, ruleSet); + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); } - internal static PBEParameter Decode(Asn1Tag expectedTag, ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValuePBEParameter decoded) { try { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); - DecodeCore(ref reader, expectedTag, encoded, out PBEParameter decoded); + DecodeCore(ref reader, expectedTag, out decoded); reader.ThrowIfNotEmpty(); - return decoded; } catch (AsnContentException e) { @@ -49,16 +48,16 @@ internal static PBEParameter Decode(Asn1Tag expectedTag, ReadOnlyMemory en } } - internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebind, out PBEParameter decoded) + internal static void Decode(scoped ref ValueAsnReader reader, out ValuePBEParameter 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 rebind, out PBEParameter decoded) + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValuePBEParameter decoded) { try { - DecodeCore(ref reader, expectedTag, rebind, out decoded); + DecodeCore(ref reader, expectedTag, out decoded); } catch (AsnContentException e) { @@ -66,18 +65,16 @@ internal static void Decode(ref ValueAsnReader reader, Asn1Tag expectedTag, Read } } - private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out PBEParameter decoded) + private static void DecodeCore(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValuePBEParameter decoded) { decoded = default; ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); - ReadOnlySpan rebindSpan = rebind.Span; - int offset; ReadOnlySpan tmpSpan; if (sequenceReader.TryReadPrimitiveOctetString(out tmpSpan)) { - decoded.Salt = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.Salt = tmpSpan; } else { diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml index a313795eefe02b..0cf5926c2368db 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="ref"> - - - \ No newline at end of file + + + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml.cs index 46a5de36e3104b..ba71dee2ce87e9 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PBES2Params.xml.cs @@ -9,10 +9,10 @@ namespace System.Security.Cryptography.Asn1 { [StructLayout(LayoutKind.Sequential)] - internal partial struct PBES2Params + internal ref partial struct ValuePBES2Params { - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn KeyDerivationFunc; - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn EncryptionScheme; + internal System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn KeyDerivationFunc; + internal System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn EncryptionScheme; internal readonly void Encode(AsnWriter writer) { @@ -28,20 +28,19 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) writer.PopSequence(tag); } - internal static PBES2Params Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValuePBES2Params decoded) { - return Decode(Asn1Tag.Sequence, encoded, ruleSet); + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); } - internal static PBES2Params Decode(Asn1Tag expectedTag, ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValuePBES2Params decoded) { try { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); - DecodeCore(ref reader, expectedTag, encoded, out PBES2Params decoded); + DecodeCore(ref reader, expectedTag, out decoded); reader.ThrowIfNotEmpty(); - return decoded; } catch (AsnContentException e) { @@ -49,16 +48,16 @@ internal static PBES2Params Decode(Asn1Tag expectedTag, ReadOnlyMemory enc } } - internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebind, out PBES2Params decoded) + internal static void Decode(scoped ref ValueAsnReader reader, out ValuePBES2Params 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 rebind, out PBES2Params decoded) + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValuePBES2Params decoded) { try { - DecodeCore(ref reader, expectedTag, rebind, out decoded); + DecodeCore(ref reader, expectedTag, out decoded); } catch (AsnContentException e) { @@ -66,13 +65,13 @@ internal static void Decode(ref ValueAsnReader reader, Asn1Tag expectedTag, Read } } - private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out PBES2Params decoded) + private static void DecodeCore(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValuePBES2Params decoded) { decoded = default; ValueAsnReader 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); + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref sequenceReader, out decoded.KeyDerivationFunc); + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref sequenceReader, out decoded.EncryptionScheme); sequenceReader.ThrowIfNotEmpty(); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml index 3f9723b3d862dc..0e4af860fada9d 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="ref"> - + - - + + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml.cs index 0012541c13dbf3..f38cb1acb409ee 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2Params.xml.cs @@ -15,24 +15,23 @@ file static class SharedPbkdf2Params #if DEBUG static SharedPbkdf2Params() { - Pbkdf2Params decoded = default; - ReadOnlyMemory rebind = default; + ValuePbkdf2Params decoded = default; ValueAsnReader reader; reader = new ValueAsnReader(SharedPbkdf2Params.DefaultPrf, AsnEncodingRules.DER); - System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.Prf); + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref reader, out decoded.Prf); reader.ThrowIfNotEmpty(); } #endif } [StructLayout(LayoutKind.Sequential)] - internal partial struct Pbkdf2Params + internal ref partial struct ValuePbkdf2Params { - internal System.Security.Cryptography.Asn1.Pbkdf2SaltChoice Salt; + internal System.Security.Cryptography.Asn1.ValuePbkdf2SaltChoice Salt; internal int IterationCount; internal int? KeyLength; - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn Prf; + internal System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn Prf; internal readonly void Encode(AsnWriter writer) { @@ -66,20 +65,19 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) writer.PopSequence(tag); } - internal static Pbkdf2Params Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValuePbkdf2Params decoded) { - return Decode(Asn1Tag.Sequence, encoded, ruleSet); + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); } - internal static Pbkdf2Params Decode(Asn1Tag expectedTag, ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValuePbkdf2Params decoded) { try { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); - DecodeCore(ref reader, expectedTag, encoded, out Pbkdf2Params decoded); + DecodeCore(ref reader, expectedTag, out decoded); reader.ThrowIfNotEmpty(); - return decoded; } catch (AsnContentException e) { @@ -87,16 +85,16 @@ internal static Pbkdf2Params Decode(Asn1Tag expectedTag, ReadOnlyMemory en } } - internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebind, out Pbkdf2Params decoded) + internal static void Decode(scoped ref ValueAsnReader reader, out ValuePbkdf2Params 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 rebind, out Pbkdf2Params decoded) + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValuePbkdf2Params decoded) { try { - DecodeCore(ref reader, expectedTag, rebind, out decoded); + DecodeCore(ref reader, expectedTag, out decoded); } catch (AsnContentException e) { @@ -104,13 +102,13 @@ internal static void Decode(ref ValueAsnReader reader, Asn1Tag expectedTag, Read } } - private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out Pbkdf2Params decoded) + private static void DecodeCore(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValuePbkdf2Params decoded) { decoded = default; ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); ValueAsnReader defaultReader; - System.Security.Cryptography.Asn1.Pbkdf2SaltChoice.Decode(ref sequenceReader, rebind, out decoded.Salt); + System.Security.Cryptography.Asn1.ValuePbkdf2SaltChoice.Decode(ref sequenceReader, out decoded.Salt); if (!sequenceReader.TryReadInt32(out decoded.IterationCount)) { @@ -135,12 +133,12 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence)) { - System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref sequenceReader, rebind, out decoded.Prf); + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref sequenceReader, out decoded.Prf); } else { defaultReader = new ValueAsnReader(SharedPbkdf2Params.DefaultPrf, AsnEncodingRules.DER); - System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.Prf); + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref defaultReader, out decoded.Prf); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml index 4d1e0d6a1128be..88c79e43c346b4 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="ref"> - - \ No newline at end of file + + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml.cs index e816489548d4ac..5e99e95bd6bf4c 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pbkdf2SaltChoice.xml.cs @@ -8,14 +8,10 @@ namespace System.Security.Cryptography.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct Pbkdf2SaltChoice - { - internal ReadOnlyMemory? Specified; - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn? OtherSource; - #if DEBUG - static Pbkdf2SaltChoice() + file static class ValidatePbkdf2SaltChoice + { + static ValidatePbkdf2SaltChoice() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -31,27 +27,68 @@ static Pbkdf2SaltChoice() ensureUniqueTag(Asn1Tag.PrimitiveOctetString, "Specified"); ensureUniqueTag(Asn1Tag.Sequence, "OtherSource"); } + + [System.Runtime.CompilerServices.MethodImpl( + System.Runtime.CompilerServices.MethodImplOptions.NoInlining | + System.Runtime.CompilerServices.MethodImplOptions.NoOptimization)] + internal static void Validate() { } + } +#endif + + [StructLayout(LayoutKind.Sequential)] + internal ref partial struct ValuePbkdf2SaltChoice + { + + internal ReadOnlySpan Specified + { + get; + set + { + HasSpecified = true; + field = value; + } + } + + internal bool HasSpecified { get; private set; } + + internal System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn OtherSource + { + get; + set + { + HasOtherSource = true; + field = value; + } + } + + internal bool HasOtherSource { get; private set; } + +#if DEBUG + static ValuePbkdf2SaltChoice() + { + ValidatePbkdf2SaltChoice.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) { bool wroteValue = false; - if (Specified.HasValue) + if (HasSpecified) { if (wroteValue) throw new CryptographicException(); - writer.WriteOctetString(Specified.Value.Span); + writer.WriteOctetString(Specified); wroteValue = true; } - if (OtherSource.HasValue) + if (HasOtherSource) { if (wroteValue) throw new CryptographicException(); - OtherSource.Value.Encode(writer); + OtherSource.Encode(writer); wroteValue = true; } @@ -61,15 +98,14 @@ internal readonly void Encode(AsnWriter writer) } } - internal static Pbkdf2SaltChoice Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValuePbkdf2SaltChoice decoded) { try { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); - DecodeCore(ref reader, encoded, out Pbkdf2SaltChoice decoded); + DecodeCore(ref reader, out decoded); reader.ThrowIfNotEmpty(); - return decoded; } catch (AsnContentException e) { @@ -77,11 +113,11 @@ internal static Pbkdf2SaltChoice Decode(ReadOnlyMemory encoded, AsnEncodin } } - internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebind, out Pbkdf2SaltChoice decoded) + internal static void Decode(scoped ref ValueAsnReader reader, out ValuePbkdf2SaltChoice decoded) { try { - DecodeCore(ref reader, rebind, out decoded); + DecodeCore(ref reader, out decoded); } catch (AsnContentException e) { @@ -89,12 +125,10 @@ internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebi } } - private static void DecodeCore(ref ValueAsnReader reader, ReadOnlyMemory rebind, out Pbkdf2SaltChoice decoded) + private static void DecodeCore(scoped ref ValueAsnReader reader, out ValuePbkdf2SaltChoice decoded) { decoded = default; Asn1Tag tag = reader.PeekTag(); - ReadOnlySpan rebindSpan = rebind.Span; - int offset; ReadOnlySpan tmpSpan; if (tag.HasSameClassAndValue(Asn1Tag.PrimitiveOctetString)) @@ -102,20 +136,22 @@ private static void DecodeCore(ref ValueAsnReader reader, ReadOnlyMemory r if (reader.TryReadPrimitiveOctetString(out tmpSpan)) { - decoded.Specified = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.Specified = tmpSpan; } else { decoded.Specified = reader.ReadOctetString(); } + decoded.HasSpecified = true; } else if (tag.HasSameClassAndValue(Asn1Tag.Sequence)) { - System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn tmpOtherSource; - System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out tmpOtherSource); + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn tmpOtherSource; + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref reader, out tmpOtherSource); decoded.OtherSource = tmpOtherSource; + decoded.HasOtherSource = true; } else { diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs7/CertificateChoiceAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs7/CertificateChoiceAsn.xml.cs index ccad8b1b2105af..d0d6eb900828ca 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs7/CertificateChoiceAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs7/CertificateChoiceAsn.xml.cs @@ -8,17 +8,10 @@ namespace System.Security.Cryptography.Asn1.Pkcs7 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct CertificateChoiceAsn - { - internal ReadOnlyMemory? Certificate; - internal ReadOnlyMemory? ExtendedCertificate; - internal ReadOnlyMemory? AttributeCertificateV1; - internal ReadOnlyMemory? AttributeCertificateV2; - internal System.Security.Cryptography.Asn1.Pkcs7.OtherCertificateFormat? OtherCertificateFormat; - #if DEBUG - static CertificateChoiceAsn() + file static class ValidateCertificateChoiceAsn + { + static ValidateCertificateChoiceAsn() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -37,6 +30,28 @@ static CertificateChoiceAsn() ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 2), "AttributeCertificateV2"); ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 3), "OtherCertificateFormat"); } + + [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 CertificateChoiceAsn + { + internal ReadOnlyMemory? Certificate; + internal ReadOnlyMemory? ExtendedCertificate; + internal ReadOnlyMemory? AttributeCertificateV1; + internal ReadOnlyMemory? AttributeCertificateV2; + internal System.Security.Cryptography.Asn1.Pkcs7.OtherCertificateFormat? OtherCertificateFormat; + +#if DEBUG + static CertificateChoiceAsn() + { + ValidateCertificateChoiceAsn.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs7/SignerIdentifierAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs7/SignerIdentifierAsn.xml.cs index 9c2ae529daf853..c50ef554058221 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs7/SignerIdentifierAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs7/SignerIdentifierAsn.xml.cs @@ -8,14 +8,10 @@ namespace System.Security.Cryptography.Asn1.Pkcs7 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct SignerIdentifierAsn - { - internal System.Security.Cryptography.Asn1.Pkcs7.IssuerAndSerialNumberAsn? IssuerAndSerialNumber; - internal ReadOnlyMemory? SubjectKeyIdentifier; - #if DEBUG - static SignerIdentifierAsn() + file static class ValidateSignerIdentifierAsn + { + static ValidateSignerIdentifierAsn() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -31,6 +27,25 @@ static SignerIdentifierAsn() ensureUniqueTag(Asn1Tag.Sequence, "IssuerAndSerialNumber"); ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "SubjectKeyIdentifier"); } + + [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 SignerIdentifierAsn + { + internal System.Security.Cryptography.Asn1.Pkcs7.IssuerAndSerialNumberAsn? IssuerAndSerialNumber; + internal ReadOnlyMemory? SubjectKeyIdentifier; + +#if DEBUG + static SignerIdentifierAsn() + { + ValidateSignerIdentifierAsn.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml index bfd83bb8aab9ec..d76f120e4306ce 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="both"> - + - - + + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml.cs index 44b49b66f5d4d3..f990660d39d50a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PrivateKeyInfoAsn.xml.cs @@ -134,4 +134,175 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R sequenceReader.ThrowIfNotEmpty(); } } + + [StructLayout(LayoutKind.Sequential)] + internal ref partial struct ValuePrivateKeyInfoAsn + { + internal int Version; + internal System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn PrivateKeyAlgorithm; + internal ReadOnlySpan PrivateKey; + + internal ReadOnlySpan Attributes + { + get; + set + { + HasAttributes = true; + field = value; + } + } + + internal bool HasAttributes { get; private set; } + + internal readonly void Encode(AsnWriter writer) + { + Encode(writer, Asn1Tag.Sequence); + } + + internal readonly void Encode(AsnWriter writer, Asn1Tag tag) + { + writer.PushSequence(tag); + + writer.WriteInteger(Version); + PrivateKeyAlgorithm.Encode(writer); + writer.WriteOctetString(PrivateKey); + + if (HasAttributes) + { + + try + { + writer.WriteEncodedValue(Attributes); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + } + + writer.PopSequence(tag); + } + + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValuePrivateKeyInfoAsn decoded) + { + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); + } + + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValuePrivateKeyInfoAsn decoded) + { + try + { + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); + + DecodeCore(ref reader, expectedTag, out decoded); + reader.ThrowIfNotEmpty(); + } + catch (AsnContentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + } + + internal static void Decode(scoped ref ValueAsnReader reader, out ValuePrivateKeyInfoAsn decoded) + { + Decode(ref reader, Asn1Tag.Sequence, out decoded); + } + + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValuePrivateKeyInfoAsn decoded) + { + try + { + DecodeCore(ref reader, expectedTag, out decoded); + } + catch (AsnContentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + } + + private static void DecodeCore(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValuePrivateKeyInfoAsn decoded) + { + decoded = default; + ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); + ReadOnlySpan tmpSpan; + + + if (!sequenceReader.TryReadInt32(out decoded.Version)) + { + sequenceReader.ThrowIfNotEmpty(); + } + + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref sequenceReader, out decoded.PrivateKeyAlgorithm); + + if (sequenceReader.TryReadPrimitiveOctetString(out tmpSpan)) + { + decoded.PrivateKey = tmpSpan; + } + else + { + decoded.PrivateKey = sequenceReader.ReadOctetString(); + } + + + if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0))) + { + decoded.Attributes = sequenceReader.ReadEncodedValue(); + decoded.HasAttributes = true; + } + + + sequenceReader.ThrowIfNotEmpty(); + } + + + internal AttributesEnumerable GetAttributes(AsnEncodingRules ruleSet) + { + return new AttributesEnumerable(Attributes, ruleSet); + } + + internal readonly ref struct AttributesEnumerable + { + private readonly ReadOnlySpan _encoded; + private readonly AsnEncodingRules _ruleSet; + + internal AttributesEnumerable(ReadOnlySpan encoded, AsnEncodingRules ruleSet) + { + _encoded = encoded; + _ruleSet = ruleSet; + } + + public Enumerator GetEnumerator() => new Enumerator(_encoded, _ruleSet); + + internal ref struct Enumerator + { + private ValueAsnReader _reader; + private System.Security.Cryptography.Asn1.ValueAttributeAsn _current; + + internal Enumerator(ReadOnlySpan encoded, AsnEncodingRules ruleSet) + { + if (!encoded.IsEmpty) + { + ValueAsnReader outerReader = new ValueAsnReader(encoded, ruleSet); + _reader = outerReader.ReadSetOf(new Asn1Tag(TagClass.ContextSpecific, 0)); + outerReader.ThrowIfNotEmpty(); + } + + _current = default; + } + + public System.Security.Cryptography.Asn1.ValueAttributeAsn Current => _current; + + public bool MoveNext() + { + if (!_reader.HasData) + { + return false; + } + + System.Security.Cryptography.Asn1.ValueAttributeAsn.Decode(ref _reader, out _current); + return true; + } + } + } + } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.manual.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.manual.cs index 9dede0a3d7d312..ddd484e0caf9f6 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.manual.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.manual.cs @@ -6,62 +6,6 @@ namespace System.Security.Cryptography.Asn1 { - internal partial struct PssParamsAsn - { - internal RSASignaturePadding GetSignaturePadding( - int? digestValueLength = null) - { - if (TrailerField != 1) - { - throw new CryptographicException(SR.Cryptography_Pkcs_InvalidSignatureParameters); - } - - if (MaskGenAlgorithm.Algorithm != Oids.Mgf1) - { - throw new CryptographicException( - SR.Cryptography_Pkcs_PssParametersMgfNotSupported, - MaskGenAlgorithm.Algorithm); - } - - if (MaskGenAlgorithm.Parameters == null) - { - throw new CryptographicException(SR.Cryptography_Pkcs_InvalidSignatureParameters); - } - - AlgorithmIdentifierAsn mgfParams = AlgorithmIdentifierAsn.Decode( - MaskGenAlgorithm.Parameters.Value, - AsnEncodingRules.DER); - - if (mgfParams.Algorithm != HashAlgorithm.Algorithm) - { - throw new CryptographicException( - SR.Format( - SR.Cryptography_Pkcs_PssParametersMgfHashMismatch, - mgfParams.Algorithm, - HashAlgorithm.Algorithm)); - } - - int saltSize = digestValueLength.GetValueOrDefault(); - - if (!digestValueLength.HasValue) - { - saltSize = Helpers.HashOidToByteLength(HashAlgorithm.Algorithm); - } - - if (SaltLength != saltSize) - { - throw new CryptographicException( - SR.Format( - SR.Cryptography_Pkcs_PssParametersSaltMismatch, - SaltLength, - HashAlgorithm.Algorithm)); - } - - // When RSASignaturePadding supports custom salt sizes this return will look different. - return RSASignaturePadding.Pss; - } - } - internal ref partial struct ValuePssParamsAsn { internal RSASignaturePadding GetSignaturePadding(int? digestValueLength = null) diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml index e3e3f32adf9f51..6bbc19f798a745 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml @@ -3,7 +3,7 @@ xmlns:asn="http://schemas.dot.net/asnxml/201808/" name="PssParamsAsn" namespace="System.Security.Cryptography.Asn1" - emitType="both"> + emitType="ref"> diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml.cs index 43e8ff1f4c64ad..eedcfe08818ec7 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml.cs @@ -21,16 +21,15 @@ file static class SharedPssParamsAsn #if DEBUG static SharedPssParamsAsn() { - PssParamsAsn decoded = default; - ReadOnlyMemory rebind = default; + ValuePssParamsAsn decoded = default; ValueAsnReader reader; reader = new ValueAsnReader(SharedPssParamsAsn.DefaultHashAlgorithm, AsnEncodingRules.DER); - System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashAlgorithm); + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref reader, out decoded.HashAlgorithm); reader.ThrowIfNotEmpty(); reader = new ValueAsnReader(SharedPssParamsAsn.DefaultMaskGenAlgorithm, AsnEncodingRules.DER); - System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.MaskGenAlgorithm); + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref reader, out decoded.MaskGenAlgorithm); reader.ThrowIfNotEmpty(); reader = new ValueAsnReader(SharedPssParamsAsn.DefaultSaltLength, AsnEncodingRules.DER); @@ -55,10 +54,10 @@ static SharedPssParamsAsn() } [StructLayout(LayoutKind.Sequential)] - internal partial struct PssParamsAsn + internal ref partial struct ValuePssParamsAsn { - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm; - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenAlgorithm; + internal System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn HashAlgorithm; + internal System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn MaskGenAlgorithm; internal int SaltLength; internal int TrailerField; @@ -132,136 +131,6 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) writer.PopSequence(tag); } - internal static PssParamsAsn Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) - { - return Decode(Asn1Tag.Sequence, encoded, ruleSet); - } - - internal static PssParamsAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory encoded, AsnEncodingRules ruleSet) - { - try - { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); - - DecodeCore(ref reader, expectedTag, encoded, out PssParamsAsn 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 rebind, out PssParamsAsn decoded) - { - Decode(ref reader, Asn1Tag.Sequence, rebind, out decoded); - } - - internal static void Decode(ref ValueAsnReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out PssParamsAsn decoded) - { - try - { - DecodeCore(ref reader, expectedTag, rebind, out decoded); - } - catch (AsnContentException e) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); - } - } - - private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out PssParamsAsn decoded) - { - decoded = default; - ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); - ValueAsnReader explicitReader; - ValueAsnReader 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(ref explicitReader, rebind, out decoded.HashAlgorithm); - explicitReader.ThrowIfNotEmpty(); - } - else - { - defaultReader = new ValueAsnReader(SharedPssParamsAsn.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(ref explicitReader, rebind, out decoded.MaskGenAlgorithm); - explicitReader.ThrowIfNotEmpty(); - } - else - { - defaultReader = new ValueAsnReader(SharedPssParamsAsn.DefaultMaskGenAlgorithm, AsnEncodingRules.DER); - System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.MaskGenAlgorithm); - } - - - if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 2))) - { - explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 2)); - - if (!explicitReader.TryReadInt32(out decoded.SaltLength)) - { - explicitReader.ThrowIfNotEmpty(); - } - - explicitReader.ThrowIfNotEmpty(); - } - else - { - defaultReader = new ValueAsnReader(SharedPssParamsAsn.DefaultSaltLength, AsnEncodingRules.DER); - - if (!defaultReader.TryReadInt32(out decoded.SaltLength)) - { - defaultReader.ThrowIfNotEmpty(); - } - - } - - - if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 3))) - { - explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 3)); - - if (!explicitReader.TryReadInt32(out decoded.TrailerField)) - { - explicitReader.ThrowIfNotEmpty(); - } - - explicitReader.ThrowIfNotEmpty(); - } - else - { - defaultReader = new ValueAsnReader(SharedPssParamsAsn.DefaultTrailerField, AsnEncodingRules.DER); - - if (!defaultReader.TryReadInt32(out decoded.TrailerField)) - { - defaultReader.ThrowIfNotEmpty(); - } - - } - - - sequenceReader.ThrowIfNotEmpty(); - } - } - - [StructLayout(LayoutKind.Sequential)] - internal ref partial struct ValuePssParamsAsn - { - internal System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn HashAlgorithm; - internal System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn MaskGenAlgorithm; - internal int SaltLength; - internal int TrailerField; - internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValuePssParamsAsn decoded) { Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml index e6101a539349f9..1a27004c19ce9c 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="ref"> diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml.cs index 6b8ec4138ff738..fc47e8335df909 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPrivateKeyAsn.xml.cs @@ -9,17 +9,17 @@ namespace System.Security.Cryptography.Asn1 { [StructLayout(LayoutKind.Sequential)] - internal partial struct RSAPrivateKeyAsn + internal ref partial struct ValueRSAPrivateKeyAsn { internal int Version; - internal ReadOnlyMemory Modulus; - internal ReadOnlyMemory PublicExponent; - internal ReadOnlyMemory PrivateExponent; - internal ReadOnlyMemory Prime1; - internal ReadOnlyMemory Prime2; - internal ReadOnlyMemory Exponent1; - internal ReadOnlyMemory Exponent2; - internal ReadOnlyMemory Coefficient; + internal ReadOnlySpan Modulus; + internal ReadOnlySpan PublicExponent; + internal ReadOnlySpan PrivateExponent; + internal ReadOnlySpan Prime1; + internal ReadOnlySpan Prime2; + internal ReadOnlySpan Exponent1; + internal ReadOnlySpan Exponent2; + internal ReadOnlySpan Coefficient; internal readonly void Encode(AsnWriter writer) { @@ -31,31 +31,30 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) writer.PushSequence(tag); writer.WriteInteger(Version); - writer.WriteInteger(Modulus.Span); - writer.WriteInteger(PublicExponent.Span); - writer.WriteInteger(PrivateExponent.Span); - writer.WriteInteger(Prime1.Span); - writer.WriteInteger(Prime2.Span); - writer.WriteInteger(Exponent1.Span); - writer.WriteInteger(Exponent2.Span); - writer.WriteInteger(Coefficient.Span); + writer.WriteInteger(Modulus); + writer.WriteInteger(PublicExponent); + writer.WriteInteger(PrivateExponent); + writer.WriteInteger(Prime1); + writer.WriteInteger(Prime2); + writer.WriteInteger(Exponent1); + writer.WriteInteger(Exponent2); + writer.WriteInteger(Coefficient); writer.PopSequence(tag); } - internal static RSAPrivateKeyAsn Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueRSAPrivateKeyAsn decoded) { - return Decode(Asn1Tag.Sequence, encoded, ruleSet); + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); } - internal static RSAPrivateKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueRSAPrivateKeyAsn decoded) { try { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); - DecodeCore(ref reader, expectedTag, encoded, out RSAPrivateKeyAsn decoded); + DecodeCore(ref reader, expectedTag, out decoded); reader.ThrowIfNotEmpty(); - return decoded; } catch (AsnContentException e) { @@ -63,16 +62,16 @@ internal static RSAPrivateKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory rebind, out RSAPrivateKeyAsn decoded) + internal static void Decode(scoped ref ValueAsnReader reader, out ValueRSAPrivateKeyAsn 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 rebind, out RSAPrivateKeyAsn decoded) + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueRSAPrivateKeyAsn decoded) { try { - DecodeCore(ref reader, expectedTag, rebind, out decoded); + DecodeCore(ref reader, expectedTag, out decoded); } catch (AsnContentException e) { @@ -80,13 +79,10 @@ internal static void Decode(ref ValueAsnReader reader, Asn1Tag expectedTag, Read } } - private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out RSAPrivateKeyAsn decoded) + private static void DecodeCore(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueRSAPrivateKeyAsn decoded) { decoded = default; ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); - ReadOnlySpan rebindSpan = rebind.Span; - int offset; - ReadOnlySpan tmpSpan; if (!sequenceReader.TryReadInt32(out decoded.Version)) @@ -94,22 +90,14 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R sequenceReader.ThrowIfNotEmpty(); } - tmpSpan = sequenceReader.ReadIntegerBytes(); - decoded.Modulus = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); - tmpSpan = sequenceReader.ReadIntegerBytes(); - decoded.PublicExponent = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); - tmpSpan = sequenceReader.ReadIntegerBytes(); - decoded.PrivateExponent = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); - tmpSpan = sequenceReader.ReadIntegerBytes(); - decoded.Prime1 = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); - tmpSpan = sequenceReader.ReadIntegerBytes(); - decoded.Prime2 = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); - tmpSpan = sequenceReader.ReadIntegerBytes(); - decoded.Exponent1 = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); - tmpSpan = sequenceReader.ReadIntegerBytes(); - decoded.Exponent2 = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); - tmpSpan = sequenceReader.ReadIntegerBytes(); - decoded.Coefficient = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.Modulus = sequenceReader.ReadIntegerBytes(); + decoded.PublicExponent = sequenceReader.ReadIntegerBytes(); + decoded.PrivateExponent = sequenceReader.ReadIntegerBytes(); + decoded.Prime1 = sequenceReader.ReadIntegerBytes(); + decoded.Prime2 = sequenceReader.ReadIntegerBytes(); + decoded.Exponent1 = sequenceReader.ReadIntegerBytes(); + decoded.Exponent2 = sequenceReader.ReadIntegerBytes(); + decoded.Coefficient = sequenceReader.ReadIntegerBytes(); sequenceReader.ThrowIfNotEmpty(); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml index d74ed507512a39..3b46f03b520b4d 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="ref"> - \ No newline at end of file + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml.cs index 95a799d7cb3e3a..f9d829892576c8 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/RSAPublicKeyAsn.xml.cs @@ -9,10 +9,10 @@ namespace System.Security.Cryptography.Asn1 { [StructLayout(LayoutKind.Sequential)] - internal partial struct RSAPublicKeyAsn + internal ref partial struct ValueRSAPublicKeyAsn { - internal ReadOnlyMemory Modulus; - internal ReadOnlyMemory PublicExponent; + internal ReadOnlySpan Modulus; + internal ReadOnlySpan PublicExponent; internal readonly void Encode(AsnWriter writer) { @@ -23,25 +23,24 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) { writer.PushSequence(tag); - writer.WriteInteger(Modulus.Span); - writer.WriteInteger(PublicExponent.Span); + writer.WriteInteger(Modulus); + writer.WriteInteger(PublicExponent); writer.PopSequence(tag); } - internal static RSAPublicKeyAsn Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueRSAPublicKeyAsn decoded) { - return Decode(Asn1Tag.Sequence, encoded, ruleSet); + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); } - internal static RSAPublicKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueRSAPublicKeyAsn decoded) { try { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); - DecodeCore(ref reader, expectedTag, encoded, out RSAPublicKeyAsn decoded); + DecodeCore(ref reader, expectedTag, out decoded); reader.ThrowIfNotEmpty(); - return decoded; } catch (AsnContentException e) { @@ -49,16 +48,16 @@ internal static RSAPublicKeyAsn Decode(Asn1Tag expectedTag, ReadOnlyMemory } } - internal static void Decode(ref ValueAsnReader reader, ReadOnlyMemory rebind, out RSAPublicKeyAsn decoded) + internal static void Decode(scoped ref ValueAsnReader reader, out ValueRSAPublicKeyAsn 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 rebind, out RSAPublicKeyAsn decoded) + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueRSAPublicKeyAsn decoded) { try { - DecodeCore(ref reader, expectedTag, rebind, out decoded); + DecodeCore(ref reader, expectedTag, out decoded); } catch (AsnContentException e) { @@ -66,18 +65,13 @@ internal static void Decode(ref ValueAsnReader reader, Asn1Tag expectedTag, Read } } - private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out RSAPublicKeyAsn decoded) + private static void DecodeCore(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueRSAPublicKeyAsn decoded) { decoded = default; ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); - ReadOnlySpan rebindSpan = rebind.Span; - int offset; - ReadOnlySpan tmpSpan; - tmpSpan = sequenceReader.ReadIntegerBytes(); - decoded.Modulus = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); - tmpSpan = sequenceReader.ReadIntegerBytes(); - decoded.PublicExponent = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.Modulus = sequenceReader.ReadIntegerBytes(); + decoded.PublicExponent = sequenceReader.ReadIntegerBytes(); sequenceReader.ThrowIfNotEmpty(); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Rc2CbcParameters.manual.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Rc2CbcParameters.manual.cs index 46f0cec08c6bd9..64fbcd055e4a8a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Rc2CbcParameters.manual.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Rc2CbcParameters.manual.cs @@ -10,9 +10,9 @@ namespace System.Security.Cryptography.Asn1 // Since 3370 says to just use that alternative there's no fallback in this code for handling // just an IV which means that an effective key size of 32-bits has been chosen. Since 40-bit is the // smallest supported by .NET that's not really a problem. - internal partial struct Rc2CbcParameters + file static class Rc2CbcEncoding { - private static ReadOnlySpan Rc2EkbEncoding => + internal static ReadOnlySpan Rc2EkbEncoding => [ 0xbd, 0x56, 0xea, 0xf2, 0xa2, 0xf1, 0xac, 0x2a, 0xb0, 0x93, 0xd1, 0x9c, 0x1b, 0x33, 0xfd, 0xd0, 0x30, 0x04, 0xb6, 0xdc, 0x7d, 0xdf, 0x32, 0x4b, 0xf7, 0xcb, 0x45, 0x9b, 0x31, 0xbb, 0x21, 0x5a, @@ -31,12 +31,15 @@ internal partial struct Rc2CbcParameters 0x64, 0x6d, 0x7a, 0xd4, 0x10, 0x81, 0x44, 0xef, 0x49, 0xd6, 0xae, 0x2e, 0xdd, 0x76, 0x5c, 0x2f, 0xa7, 0x1c, 0xc9, 0x09, 0x69, 0x9a, 0x83, 0xcf, 0x29, 0x39, 0xb9, 0xe9, 0x4c, 0xff, 0x43, 0xab, ]; + } + internal partial struct Rc2CbcParameters + { internal Rc2CbcParameters(ReadOnlyMemory iv, int keySize) { Rc2Version = keySize > byte.MaxValue ? keySize : - Rc2EkbEncoding[keySize]; + Rc2CbcEncoding.Rc2EkbEncoding[keySize]; Iv = iv; } @@ -44,6 +47,14 @@ internal Rc2CbcParameters(ReadOnlyMemory iv, int keySize) internal int GetEffectiveKeyBits() => Rc2Version > byte.MaxValue ? Rc2Version : - Rc2EkbEncoding.IndexOf((byte)Rc2Version); + Rc2CbcEncoding.Rc2EkbEncoding.IndexOf((byte)Rc2Version); + } + + internal ref partial struct ValueRc2CbcParameters + { + internal int GetEffectiveKeyBits() => + Rc2Version > byte.MaxValue ? + Rc2Version : + Rc2CbcEncoding.Rc2EkbEncoding.IndexOf((byte)Rc2Version); } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Rc2CbcParameters.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Rc2CbcParameters.xml index b7dbcdc5841b9e..a1c059150652a4 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Rc2CbcParameters.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Rc2CbcParameters.xml @@ -2,14 +2,15 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="both"> - - - + + + diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml.cs index 97fec05b91f5e0..29ae27b3fdc236 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SpecifiedECDomain.xml.cs @@ -9,14 +9,25 @@ namespace System.Security.Cryptography.Asn1 { [StructLayout(LayoutKind.Sequential)] - internal partial struct SpecifiedECDomain + internal ref partial struct ValueSpecifiedECDomain { internal int Version; - internal System.Security.Cryptography.Asn1.FieldID FieldID; - internal System.Security.Cryptography.Asn1.CurveAsn Curve; - internal ReadOnlyMemory Base; - internal ReadOnlyMemory Order; - internal ReadOnlyMemory? Cofactor; + internal System.Security.Cryptography.Asn1.ValueFieldID FieldID; + internal System.Security.Cryptography.Asn1.ValueCurveAsn Curve; + internal ReadOnlySpan Base; + internal ReadOnlySpan Order; + + internal ReadOnlySpan Cofactor + { + get; + set + { + HasCofactor = true; + field = value; + } + } + + internal bool HasCofactor { get; private set; } internal string? Hash; internal readonly void Encode(AsnWriter writer) @@ -31,12 +42,12 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) writer.WriteInteger(Version); FieldID.Encode(writer); Curve.Encode(writer); - writer.WriteOctetString(Base.Span); - writer.WriteInteger(Order.Span); + writer.WriteOctetString(Base); + writer.WriteInteger(Order); - if (Cofactor.HasValue) + if (HasCofactor) { - writer.WriteInteger(Cofactor.Value.Span); + writer.WriteInteger(Cofactor); } @@ -55,20 +66,19 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) writer.PopSequence(tag); } - internal static SpecifiedECDomain Decode(ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueSpecifiedECDomain decoded) { - return Decode(Asn1Tag.Sequence, encoded, ruleSet); + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); } - internal static SpecifiedECDomain Decode(Asn1Tag expectedTag, ReadOnlyMemory encoded, AsnEncodingRules ruleSet) + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueSpecifiedECDomain decoded) { try { - ValueAsnReader reader = new ValueAsnReader(encoded.Span, ruleSet); + ValueAsnReader reader = new ValueAsnReader(encoded, ruleSet); - DecodeCore(ref reader, expectedTag, encoded, out SpecifiedECDomain decoded); + DecodeCore(ref reader, expectedTag, out decoded); reader.ThrowIfNotEmpty(); - return decoded; } catch (AsnContentException e) { @@ -76,16 +86,16 @@ internal static SpecifiedECDomain Decode(Asn1Tag expectedTag, ReadOnlyMemory rebind, out SpecifiedECDomain decoded) + internal static void Decode(scoped ref ValueAsnReader reader, out ValueSpecifiedECDomain 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 rebind, out SpecifiedECDomain decoded) + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueSpecifiedECDomain decoded) { try { - DecodeCore(ref reader, expectedTag, rebind, out decoded); + DecodeCore(ref reader, expectedTag, out decoded); } catch (AsnContentException e) { @@ -93,12 +103,10 @@ internal static void Decode(ref ValueAsnReader reader, Asn1Tag expectedTag, Read } } - private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, ReadOnlyMemory rebind, out SpecifiedECDomain decoded) + private static void DecodeCore(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueSpecifiedECDomain decoded) { decoded = default; ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); - ReadOnlySpan rebindSpan = rebind.Span; - int offset; ReadOnlySpan tmpSpan; @@ -107,25 +115,24 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R sequenceReader.ThrowIfNotEmpty(); } - System.Security.Cryptography.Asn1.FieldID.Decode(ref sequenceReader, rebind, out decoded.FieldID); - System.Security.Cryptography.Asn1.CurveAsn.Decode(ref sequenceReader, rebind, out decoded.Curve); + System.Security.Cryptography.Asn1.ValueFieldID.Decode(ref sequenceReader, out decoded.FieldID); + System.Security.Cryptography.Asn1.ValueCurveAsn.Decode(ref sequenceReader, out decoded.Curve); if (sequenceReader.TryReadPrimitiveOctetString(out tmpSpan)) { - decoded.Base = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.Base = tmpSpan; } else { decoded.Base = sequenceReader.ReadOctetString(); } - tmpSpan = sequenceReader.ReadIntegerBytes(); - decoded.Order = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.Order = sequenceReader.ReadIntegerBytes(); if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer)) { - tmpSpan = sequenceReader.ReadIntegerBytes(); - decoded.Cofactor = rebindSpan.Overlaps(tmpSpan, out offset) ? rebind.Slice(offset, tmpSpan.Length) : tmpSpan.ToArray(); + decoded.Cofactor = sequenceReader.ReadIntegerBytes(); + decoded.HasCofactor = true; } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml.cs index 80ce6bb17b408e..f7de7452f92fb7 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml.cs @@ -96,6 +96,20 @@ internal ref partial struct ValueSubjectPublicKeyInfoAsn internal System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn Algorithm; internal ReadOnlySpan SubjectPublicKey; + internal readonly void Encode(AsnWriter writer) + { + Encode(writer, Asn1Tag.Sequence); + } + + internal readonly void Encode(AsnWriter writer, Asn1Tag tag) + { + writer.PushSequence(tag); + + Algorithm.Encode(writer); + writer.WriteBitString(SubjectPublicKey, 0); + writer.PopSequence(tag); + } + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueSubjectPublicKeyInfoAsn decoded) { Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml.cs index 04efe34e8044cf..b3140132e0f5cd 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml.cs @@ -147,6 +147,40 @@ internal ref partial struct ValueX509ExtensionAsn internal bool Critical; internal ReadOnlySpan ExtnValue; + internal readonly void Encode(AsnWriter writer) + { + Encode(writer, Asn1Tag.Sequence); + } + + internal readonly void Encode(AsnWriter writer, Asn1Tag tag) + { + writer.PushSequence(tag); + + try + { + writer.WriteObjectIdentifier(ExtnId); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + + // DEFAULT value handler for Critical. + { + const int AsnBoolDerEncodeSize = 3; + AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER, initialCapacity: AsnBoolDerEncodeSize); + tmp.WriteBoolean(Critical); + + if (!tmp.EncodedValueEquals(SharedX509ExtensionAsn.DefaultCritical)) + { + tmp.CopyTo(writer); + } + } + + writer.WriteOctetString(ExtnValue); + writer.PopSequence(tag); + } + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueX509ExtensionAsn decoded) { Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/asn.xslt b/src/libraries/Common/src/System/Security/Cryptography/Asn1/asn.xslt index 0768fd3cf3e9c6..72d14b2981bd56 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/asn.xslt +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/asn.xslt @@ -67,16 +67,17 @@ namespace { file static class Shared { -#if DEBUG +#if DEBUG static Shared() { - decoded = default; + decoded = default; ReadOnlyMemory<byte> rebind = default; ValueAsnReader reader; - ValueAsnReader collectionReader; + ValueAsnReader collectionReader; Value decoded = default; + ValueAsnReader reader; } #endif - } + } [StructLayout(LayoutKind.Sequential)] internal partial struct @@ -152,6 +153,18 @@ namespace internal ref partial struct Value { + internal readonly void Encode(AsnWriter writer) + { + Encode(writer, Asn1Tag.Sequence); + } + + internal readonly void Encode(AsnWriter writer, Asn1Tag tag) + { + writer.PushSequence(tag); + + writer.PopSequence(tag); + } + internal static void Decode(ReadOnlySpan<byte> encoded, AsnEncodingRules ruleSet, out Value decoded) { Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); @@ -214,13 +227,11 @@ using System.Formats.Asn1; using System.Runtime.InteropServices; namespace -{ - [StructLayout(LayoutKind.Sequential)] - internal partial struct - { - +{ #if DEBUG - static () + file static class Validate + { + static Validate() { var usedTags = new System.Collections.Generic.Dictionary<Asn1Tag, string>(); Action<Asn1Tag, string> ensureUniqueTag = (tag, fieldName) => @@ -234,6 +245,23 @@ namespace }; } + + [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 + { + +#if DEBUG + static () + { + Validate.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) @@ -295,6 +323,23 @@ namespace internal ref partial struct Value { +#if DEBUG + static Value() + { + Validate.Validate(); + } +#endif + + internal readonly void Encode(AsnWriter writer) + { + bool wroteValue = false; + + if (!wroteValue) + { + throw new CryptographicException(); + } + } + internal static void Decode(ReadOnlySpan<byte> encoded, AsnEncodingRules ruleSet, out Value decoded) { try @@ -363,6 +408,13 @@ namespace reader = new ValueAsnReader(, AsnEncodingRules.DER); reader.ThrowIfNotEmpty(); + + + reader = new ValueAsnReader(, AsnEncodingRules.DER); + reader.ThrowIfNotEmpty(); + + + @@ -1071,37 +1123,59 @@ namespace - - internal ReadOnlySpan<byte> ; - internal bool Has; + + ReadOnlySpan<byte> + - - internal ReadOnlySpan<byte> ; - internal bool Has; + + ReadOnlySpan<byte> + - - internal ReadOnlySpan<byte> ; - internal bool Has; + + ReadOnlySpan<byte> + - - internal ReadOnlySpan<byte> ; - internal bool Has; + + ReadOnlySpan<byte> + - - internal ReadOnlySpan<byte> ; - internal bool Has; + + ReadOnlySpan<byte> + - - internal ; - internal bool Has; + + + internal ? ; - - internal ReadOnlySpan<byte> ; - internal bool Has; + + ReadOnlySpan<byte> + + + + + + + + + internal + { + get; + set + { + Has = true; + field = value; + } + } + + internal bool Has { get; private set; } + + internal ; + + @@ -1401,4 +1475,278 @@ namespace + + + + + + + + // DEFAULT value handler for . + { + + + + + + + + if (!tmp.EncodedValueEquals()) + { + tmp.CopyTo(writer); + } + } + + + + + + + + + + + + + + + + + if (Has) + { + } + + + + if ( != null) + { + } + + + + if (.HasValue) + { + } + + + + + + + + + + + + // DEFAULT value handler for . + { + + + + + + + + if (!tmp.EncodedValueEquals()) + { + writer.PushSequence(); + tmp.CopyTo(writer); + writer.PopSequence(); + } + } + + + writer.PushSequence(); + writer.PopSequence(); + + + + + + + + + + + + + + + + + + + + + + + + + + + + // Validator for tag constraint for + { + if (!Asn1Tag.TryDecode(, out Asn1Tag validateTag, out _) || + !validateTag.HasSameClassAndValue()) + { + throw new CryptographicException(); + } + } + + + + try + { + .WriteEncodedValue(); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + + + + + + + + + .WriteOctetString(); + + + + + + + + + .WriteBitString(, 0); + + + + + + + + + .WriteInteger(); + + + + + + + + + .Encode(); + + + + + + + + + + try + { + .WriteEncodedValue(); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + + + + + + + + + + try + { + .WriteEncodedValue(); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + + + + + + + if (Has) + { + if (wroteValue) + throw new CryptographicException(); + + wroteValue = true; + } + + + + if (Has) + { + if (wroteValue) + throw new CryptographicException(); + + wroteValue = true; + } + + + + if (Has) + { + if (wroteValue) + throw new CryptographicException(); + + wroteValue = true; + } + + + + if (Has) + { + if (wroteValue) + throw new CryptographicException(); + + wroteValue = true; + } + + + + + if (.HasValue) + { + if (wroteValue) + throw new CryptographicException(); + + wroteValue = true; + } + + + + + if ( != null) + { + if (wroteValue) + throw new CryptographicException(); + + wroteValue = true; + } + + diff --git a/src/libraries/Common/src/System/Security/Cryptography/CngPkcs8.cs b/src/libraries/Common/src/System/Security/Cryptography/CngPkcs8.cs index 8d086244207ac9..31d3d047532d65 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/CngPkcs8.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/CngPkcs8.cs @@ -391,40 +391,34 @@ private static AsnWriter RewriteEncryptedPkcs8PrivateKey( // signaling the original exception should be thrown. private static unsafe AsnWriter? RewritePkcs8ECPrivateKeyWithZeroPublicKey(ReadOnlySpan source) { - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) + ValuePrivateKeyInfoAsn.Decode(source, AsnEncodingRules.BER, out ValuePrivateKeyInfoAsn privateKeyInfo); + ValueAlgorithmIdentifierAsn privateAlgorithm = privateKeyInfo.PrivateKeyAlgorithm; + + if (privateAlgorithm.Algorithm != Oids.EcPublicKey) { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - PrivateKeyInfoAsn privateKeyInfo = PrivateKeyInfoAsn.Decode(manager.Memory, AsnEncodingRules.BER); - AlgorithmIdentifierAsn privateAlgorithm = privateKeyInfo.PrivateKeyAlgorithm; + return null; + } + + ValueECPrivateKey.Decode(privateKeyInfo.PrivateKey, AsnEncodingRules.BER, out ValueECPrivateKey privateKey); + EccKeyFormatHelper.FromECPrivateKey(privateKey, privateAlgorithm, out ECParameters ecParameters); - if (privateAlgorithm.Algorithm != Oids.EcPublicKey) + fixed (byte* pD = ecParameters.D) + { + try + { + if (!ecParameters.Curve.IsExplicit || ecParameters.Q.X != null || ecParameters.Q.Y != null) { return null; } - ECPrivateKey privateKey = ECPrivateKey.Decode(privateKeyInfo.PrivateKey, AsnEncodingRules.BER); - EccKeyFormatHelper.FromECPrivateKey(privateKey, privateAlgorithm, out ECParameters ecParameters); - - fixed (byte* pD = ecParameters.D) - { - try - { - if (!ecParameters.Curve.IsExplicit || ecParameters.Q.X != null || ecParameters.Q.Y != null) - { - return null; - } - - byte[] zero = new byte[ecParameters.D!.Length]; - ecParameters.Q.Y = zero; - ecParameters.Q.X = zero; - return EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters, privateKeyInfo.Attributes); - } - finally - { - Array.Clear(ecParameters.D!); - } - } + byte[] zero = new byte[ecParameters.D!.Length]; + ecParameters.Q.Y = zero; + ecParameters.Q.X = zero; + return EccKeyFormatHelper.WritePkcs8PrivateKey(ecParameters, privateKeyInfo.Attributes); + } + finally + { + Array.Clear(ecParameters.D!); } } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsa.cs b/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsa.cs index 78eb7b5415376d..8145cdcdcd6e4a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsa.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/CompositeMLDsa.cs @@ -670,7 +670,7 @@ public static CompositeMLDsa ImportSubjectPublicKeyInfo(ReadOnlySpan sourc Debug.Assert(read == source.Length); return dsa; - static void SubjectPublicKeyReader(ReadOnlyMemory key, in AlgorithmIdentifierAsn identifier, out CompositeMLDsa dsa) + static void SubjectPublicKeyReader(ReadOnlySpan key, in ValueAlgorithmIdentifierAsn identifier, out CompositeMLDsa dsa) { CompositeMLDsaAlgorithm algorithm = GetAlgorithmIdentifier(in identifier); @@ -679,7 +679,7 @@ static void SubjectPublicKeyReader(ReadOnlyMemory key, in AlgorithmIdentif throw new CryptographicException(SR.Argument_PublicKeyWrongSizeForAlgorithm); } - dsa = CompositeMLDsaImplementation.ImportCompositeMLDsaPublicKeyImpl(algorithm, key.Span); + dsa = CompositeMLDsaImplementation.ImportCompositeMLDsaPublicKeyImpl(algorithm, key); } } @@ -861,8 +861,8 @@ public static CompositeMLDsa ImportPkcs8PrivateKey(ReadOnlySpan source) return dsa; static void PrivateKeyReader( - ReadOnlyMemory privateKeyContents, - in AlgorithmIdentifierAsn algorithmIdentifier, + ReadOnlySpan privateKeyContents, + in ValueAlgorithmIdentifierAsn algorithmIdentifier, out CompositeMLDsa dsa) { CompositeMLDsaAlgorithm algorithm = GetAlgorithmIdentifier(in algorithmIdentifier); @@ -872,7 +872,7 @@ static void PrivateKeyReader( throw new CryptographicException(SR.Argument_PrivateKeyWrongSizeForAlgorithm); } - dsa = CompositeMLDsaImplementation.ImportCompositeMLDsaPrivateKeyImpl(algorithm, privateKeyContents.Span); + dsa = CompositeMLDsaImplementation.ImportCompositeMLDsaPrivateKeyImpl(algorithm, privateKeyContents); } } @@ -1910,16 +1910,14 @@ private TResult ExportPkcs8PrivateKeyCallback(ProcessExportedContent source) + public static ECDsaComponent ImportPrivateKey(ECDsaAlgorithm algorithm, ReadOnlySpan source) { Helpers.ThrowIfAsnInvalidLength(source); - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - ECPrivateKey ecPrivateKey = ECPrivateKey.Decode(manager.Memory, AsnEncodingRules.BER); + ValueECPrivateKey.Decode(source, AsnEncodingRules.BER, out ValueECPrivateKey ecPrivateKey); - if (ecPrivateKey.Version != 1 || - ecPrivateKey.PublicKey is not null) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); - } + if (ecPrivateKey.Version != 1 || ecPrivateKey.HasPublicKey) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } - if (ecPrivateKey.Parameters?.Named != algorithm.CurveOidValue) - { - // The curve specified must be named and match the required curve for the Composite ML-DSA algorithm. - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); - } + if (!ecPrivateKey.HasParameters || ecPrivateKey.Parameters.Named != algorithm.CurveOidValue) + { + // The curve specified must be named and match the required curve for the Composite ML-DSA algorithm. + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } - byte[] d = new byte[ecPrivateKey.PrivateKey.Length]; + byte[] d = new byte[ecPrivateKey.PrivateKey.Length]; - using (PinAndClear.Track(d)) - { - ecPrivateKey.PrivateKey.CopyTo(d); + using (PinAndClear.Track(d)) + { + ecPrivateKey.PrivateKey.CopyTo(d); #if NET || NETSTANDARD - ECParameters parameters = new ECParameters - { - Curve = algorithm.Curve, - Q = new ECPoint - { - X = null, - Y = null, - }, - D = d - }; + ECParameters parameters = new ECParameters + { + Curve = algorithm.Curve, + Q = new ECPoint + { + X = null, + Y = null, + }, + D = d + }; - parameters.Validate(); + parameters.Validate(); - return new ECDsaComponent(ECDsa.Create(parameters), algorithm); + return new ECDsaComponent(ECDsa.Create(parameters), algorithm); #else // NETFRAMEWORK #if NET472_OR_GREATER #error ECDsa.Create(ECParameters) is avaliable in .NET Framework 4.7.2 and later, so this workaround is not needed anymore. #endif - Debug.Assert(!string.IsNullOrEmpty(algorithm.CurveOid.FriendlyName)); + Debug.Assert(!string.IsNullOrEmpty(algorithm.CurveOid.FriendlyName)); - byte[] zero = new byte[d.Length]; - byte[] x = zero; - byte[] y = zero; + byte[] zero = new byte[d.Length]; + byte[] x = zero; + byte[] y = zero; - if (!TryValidateNamedCurve(x, y, d)) - { - throw new CryptographicException(SR.Cryptography_InvalidECPrivateKeyParameters); - } - - return new ECDsaComponent( - ECCng.EncodeEccKeyBlob( - algorithm.PrivateKeyBlobMagicNumber, - x, - y, - d, - blob => ImportKeyBlob(blob, algorithm.CurveOid.FriendlyName, includePrivateParameters: true)), - algorithm); -#endif - } + if (!TryValidateNamedCurve(x, y, d)) + { + throw new CryptographicException(SR.Cryptography_InvalidECPrivateKeyParameters); } + + return new ECDsaComponent( + ECCng.EncodeEccKeyBlob( + algorithm.PrivateKeyBlobMagicNumber, + x, + y, + d, + blob => ImportKeyBlob(blob, algorithm.CurveOid.FriendlyName, includePrivateParameters: true)), + algorithm); +#endif } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs index a20e3b0e92d9bf..c4f7baa328dffd 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/DSAKeyFormatHelper.cs @@ -16,11 +16,11 @@ internal static class DSAKeyFormatHelper }; internal static void ReadDsaPrivateKey( - ReadOnlyMemory xBytes, - in AlgorithmIdentifierAsn algId, + ReadOnlySpan xBytes, + in ValueAlgorithmIdentifierAsn algId, out DSAParameters ret) { - if (!algId.Parameters.HasValue) + if (!algId.HasParameters) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } @@ -30,7 +30,7 @@ internal static void ReadDsaPrivateKey( try { ReadOnlySpan xSpan = AsnDecoder.ReadIntegerBytes( - xBytes.Span, + xBytes, AsnEncodingRules.DER, out int consumed); @@ -47,7 +47,7 @@ internal static void ReadDsaPrivateKey( throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } - DssParms parms = DssParms.Decode(algId.Parameters.Value, AsnEncodingRules.BER); + ValueDssParms.Decode(algId.Parameters, AsnEncodingRules.BER, out ValueDssParms parms); // Sanity checks from FIPS 186-4 4.1/4.2. Since FIPS 186-5 withdrew DSA/DSS // these will never change again. @@ -82,11 +82,11 @@ internal static void ReadDsaPrivateKey( } internal static void ReadDsaPublicKey( - ReadOnlyMemory yBytes, - in AlgorithmIdentifierAsn algId, + ReadOnlySpan yBytes, + in ValueAlgorithmIdentifierAsn algId, out DSAParameters ret) { - if (!algId.Parameters.HasValue) + if (!algId.HasParameters) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } @@ -96,7 +96,7 @@ internal static void ReadDsaPublicKey( try { y = AsnDecoder.ReadInteger( - yBytes.Span, + yBytes, AsnEncodingRules.DER, out int consumed); @@ -110,7 +110,7 @@ internal static void ReadDsaPublicKey( throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } - DssParms parms = DssParms.Decode(algId.Parameters.Value, AsnEncodingRules.BER); + ValueDssParms.Decode(algId.Parameters, AsnEncodingRules.BER, out ValueDssParms parms); // Sanity checks from FIPS 186-4 4.1/4.2. Since FIPS 186-5 withdrew DSA/DSS // these will never change again. @@ -172,16 +172,6 @@ internal static void ReadSubjectPublicKeyInfo( out key); } - internal static ReadOnlyMemory ReadSubjectPublicKeyInfo( - ReadOnlyMemory source, - out int bytesRead) - { - return KeyFormatHelper.ReadSubjectPublicKeyInfo( - s_validOids, - source, - out bytesRead); - } - internal static void ReadPkcs8( ReadOnlySpan source, out int bytesRead, diff --git a/src/libraries/Common/src/System/Security/Cryptography/Helpers.cs b/src/libraries/Common/src/System/Security/Cryptography/Helpers.cs index dc743c3e6112df..d43568bf5427f1 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Helpers.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Helpers.cs @@ -9,6 +9,7 @@ using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security.Cryptography; +using System.Security.Cryptography.Asn1; namespace Internal.Cryptography { @@ -213,8 +214,10 @@ internal static IncrementalHash CreateIncrementalHash(HashAlgorithmName hashAlgo } } - internal static CryptographicException CreateAlgorithmUnknownException(AsnWriter encodedId) + internal static CryptographicException CreateAlgorithmUnknownException(ref readonly ValueAlgorithmIdentifierAsn identifier) { + AsnWriter encodedId = new(AsnEncodingRules.DER); + identifier.Encode(encodedId); #if NET return encodedId.Encode(static encoded => CreateAlgorithmUnknownException(Convert.ToHexString(encoded))); #else diff --git a/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs b/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs index d2570a9173dc19..80dd2e736b0937 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/KeyBlobHelpers.cs @@ -8,42 +8,52 @@ namespace System.Security.Cryptography { internal static partial class KeyBlobHelpers { - internal static byte[] ToUnsignedIntegerBytes(this ReadOnlyMemory memory) + internal static byte[] ToUnsignedIntegerBytes(this ReadOnlySpan span) { - if (memory.Length > 1 && memory.Span[0] == 0) + if (span.Length > 1 && span[0] == 0) { - return memory.Slice(1).ToArray(); + return span.Slice(1).ToArray(); } - return memory.ToArray(); + return span.ToArray(); + } + + internal static byte[] ToUnsignedIntegerBytes(this ReadOnlyMemory memory) + { + return ToUnsignedIntegerBytes(memory.Span); } internal static void ToUnsignedIntegerBytes(this ReadOnlyMemory memory, Span destination) + { + ToUnsignedIntegerBytes(memory.Span, destination); + } + + internal static void ToUnsignedIntegerBytes(this ReadOnlySpan span, Span destination) { int length = destination.Length; - if (memory.Length == length) + if (span.Length == length) { - memory.Span.CopyTo(destination); + span.CopyTo(destination); return; } - if (memory.Length == length + 1) + if (span.Length == length + 1) { - if (memory.Span[0] == 0) + if (span[0] == 0) { - memory.Span.Slice(1).CopyTo(destination); + span.Slice(1).CopyTo(destination); return; } } - if (memory.Length > length) + if (span.Length > length) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - destination.Slice(0, destination.Length - memory.Length).Clear(); - memory.Span.CopyTo(destination.Slice(length - memory.Length)); + destination.Slice(0, destination.Length - span.Length).Clear(); + span.CopyTo(destination.Slice(length - span.Length)); } internal static void WriteKeyParameterInteger(this AsnWriter writer, ReadOnlySpan integer) diff --git a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.Encrypted.cs b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.Encrypted.cs index d4dcad048d2384..e3616e7766faf7 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.Encrypted.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.Encrypted.cs @@ -14,53 +14,13 @@ internal static partial class KeyFormatHelper { internal delegate TRet ReadOnlySpanFunc(ReadOnlySpan span); - internal static unsafe void ReadEncryptedPkcs8( + internal static void ReadEncryptedPkcs8( string[] validOids, ReadOnlySpan source, ReadOnlySpan password, KeyReader keyReader, out int bytesRead, out TRet ret) - { - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - ReadEncryptedPkcs8(validOids, manager.Memory, password, keyReader, out bytesRead, out ret); - } - } - } - - internal static unsafe void ReadEncryptedPkcs8( - string[] validOids, - ReadOnlySpan source, - ReadOnlySpan passwordBytes, - KeyReader keyReader, - out int bytesRead, - out TRet ret) - { - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - ReadEncryptedPkcs8( - validOids, - manager.Memory, - passwordBytes, - keyReader, - out bytesRead, - out ret); - } - } - } - - private static void ReadEncryptedPkcs8( - string[] validOids, - ReadOnlyMemory source, - ReadOnlySpan password, - KeyReader keyReader, - out int bytesRead, - out TRet ret) { ReadEncryptedPkcs8( validOids, @@ -72,9 +32,9 @@ private static void ReadEncryptedPkcs8( out ret); } - private static void ReadEncryptedPkcs8( + internal static void ReadEncryptedPkcs8( string[] validOids, - ReadOnlyMemory source, + ReadOnlySpan source, ReadOnlySpan passwordBytes, KeyReader keyReader, out int bytesRead, @@ -92,7 +52,7 @@ private static void ReadEncryptedPkcs8( private static void ReadEncryptedPkcs8( string[] validOids, - ReadOnlyMemory source, + ReadOnlySpan source, ReadOnlySpan password, ReadOnlySpan passwordBytes, KeyReader keyReader, @@ -100,13 +60,13 @@ private static void ReadEncryptedPkcs8( out TRet ret) { int read; - EncryptedPrivateKeyInfoAsn epki; + ValueEncryptedPrivateKeyInfoAsn epki; try { - ValueAsnReader reader = new ValueAsnReader(source.Span, AsnEncodingRules.BER); + ValueAsnReader reader = new ValueAsnReader(source, AsnEncodingRules.BER); read = reader.PeekEncodedValue().Length; - EncryptedPrivateKeyInfoAsn.Decode(ref reader, source, out epki); + ValueEncryptedPrivateKeyInfoAsn.Decode(ref reader, out epki); } catch (AsnContentException e) { @@ -124,14 +84,14 @@ private static void ReadEncryptedPkcs8( epki.EncryptionAlgorithm, password, passwordBytes, - epki.EncryptedData.Span, + epki.EncryptedData, decrypted); decryptedMemory = decryptedMemory.Slice(0, decryptedBytes); ReadPkcs8( validOids, - decryptedMemory, + decryptedMemory.Span, keyReader, out int innerRead, out ret); diff --git a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs index 98f2a099964a65..66dc46b83c9ef1 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/KeyFormatHelper.cs @@ -11,38 +11,23 @@ namespace System.Security.Cryptography { internal static partial class KeyFormatHelper { - internal delegate void KeyReader(ReadOnlyMemory key, in AlgorithmIdentifierAsn algId, out TRet ret); + internal delegate void KeyReader(ReadOnlySpan key, in ValueAlgorithmIdentifierAsn algId, out TRet ret); - internal static unsafe void ReadSubjectPublicKeyInfo( + internal static void ReadSubjectPublicKeyInfo( string[] validOids, ReadOnlySpan source, KeyReader keyReader, out int bytesRead, out TRet ret) { - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - ReadSubjectPublicKeyInfo(validOids, manager.Memory, keyReader, out bytesRead, out ret); - } - } - } - - internal static ReadOnlyMemory ReadSubjectPublicKeyInfo( - string[] validOids, - ReadOnlyMemory source, - out int bytesRead) - { - SubjectPublicKeyInfoAsn spki; + ValueSubjectPublicKeyInfoAsn spki; int read; try { - // X.509 SubjectPublicKeyInfo is described as DER. - ValueAsnReader reader = new ValueAsnReader(source.Span, AsnEncodingRules.DER); + ValueAsnReader reader = new ValueAsnReader(source, AsnEncodingRules.DER); read = reader.PeekEncodedValue().Length; - SubjectPublicKeyInfoAsn.Decode(ref reader, source, out spki); + ValueSubjectPublicKeyInfoAsn.Decode(ref reader, out spki); } catch (AsnContentException e) { @@ -54,26 +39,24 @@ internal static ReadOnlyMemory ReadSubjectPublicKeyInfo( throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey); } + keyReader(spki.SubjectPublicKey, spki.Algorithm, out ret); bytesRead = read; - return spki.SubjectPublicKey; } - private static void ReadSubjectPublicKeyInfo( + internal static ReadOnlySpan ReadSubjectPublicKeyInfo( string[] validOids, - ReadOnlyMemory source, - KeyReader keyReader, - out int bytesRead, - out TRet ret) + ReadOnlySpan source, + out int bytesRead) { - SubjectPublicKeyInfoAsn spki; + ValueSubjectPublicKeyInfoAsn spki; int read; try { // X.509 SubjectPublicKeyInfo is described as DER. - ValueAsnReader reader = new ValueAsnReader(source.Span, AsnEncodingRules.DER); + ValueAsnReader reader = new ValueAsnReader(source, AsnEncodingRules.DER); read = reader.PeekEncodedValue().Length; - SubjectPublicKeyInfoAsn.Decode(ref reader, source, out spki); + ValueSubjectPublicKeyInfoAsn.Decode(ref reader, out spki); } catch (AsnContentException e) { @@ -85,44 +68,31 @@ private static void ReadSubjectPublicKeyInfo( throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey); } - keyReader(spki.SubjectPublicKey, spki.Algorithm, out ret); bytesRead = read; + return spki.SubjectPublicKey; } - internal static unsafe void ReadPkcs8( + internal static void ReadPkcs8( string[] validOids, ReadOnlySpan source, KeyReader keyReader, out int bytesRead, out TRet ret) - { - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - ReadPkcs8(validOids, manager.Memory, keyReader, out bytesRead, out ret); - } - } - } - - internal static ReadOnlyMemory ReadPkcs8( - string[] validOids, - ReadOnlyMemory source, - out int bytesRead) { try { - ValueAsnReader reader = new ValueAsnReader(source.Span, AsnEncodingRules.BER); + ValueAsnReader reader = new ValueAsnReader(source, AsnEncodingRules.BER); int read = reader.PeekEncodedValue().Length; - PrivateKeyInfoAsn.Decode(ref reader, source, out PrivateKeyInfoAsn privateKeyInfo); + ValuePrivateKeyInfoAsn.Decode(ref reader, out ValuePrivateKeyInfoAsn privateKeyInfo); if (Array.IndexOf(validOids, privateKeyInfo.PrivateKeyAlgorithm.Algorithm) < 0) { throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey); } + // Fails if there are unconsumed bytes. + keyReader(privateKeyInfo.PrivateKey, privateKeyInfo.PrivateKeyAlgorithm, out ret); bytesRead = read; - return privateKeyInfo.PrivateKey; } catch (AsnContentException e) { @@ -130,27 +100,24 @@ internal static ReadOnlyMemory ReadPkcs8( } } - private static void ReadPkcs8( + internal static ReadOnlySpan ReadPkcs8( string[] validOids, - ReadOnlyMemory source, - KeyReader keyReader, - out int bytesRead, - out TRet ret) + ReadOnlySpan source, + out int bytesRead) { try { - ValueAsnReader reader = new ValueAsnReader(source.Span, AsnEncodingRules.BER); + ValueAsnReader reader = new ValueAsnReader(source, AsnEncodingRules.BER); int read = reader.PeekEncodedValue().Length; - PrivateKeyInfoAsn.Decode(ref reader, source, out PrivateKeyInfoAsn privateKeyInfo); + ValuePrivateKeyInfoAsn.Decode(ref reader, out ValuePrivateKeyInfoAsn privateKeyInfo); if (Array.IndexOf(validOids, privateKeyInfo.PrivateKeyAlgorithm.Algorithm) < 0) { throw new CryptographicException(SR.Cryptography_NotValidPublicOrPrivateKey); } - // Fails if there are unconsumed bytes. - keyReader(privateKeyInfo.PrivateKey, privateKeyInfo.PrivateKeyAlgorithm, out ret); bytesRead = read; + return privateKeyInfo.PrivateKey; } catch (AsnContentException e) { diff --git a/src/libraries/Common/src/System/Security/Cryptography/MLDsa.cs b/src/libraries/Common/src/System/Security/Cryptography/MLDsa.cs index 0b3b151ed6bbc6..21944f3c1dc180 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/MLDsa.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/MLDsa.cs @@ -1376,26 +1376,20 @@ public static MLDsa ImportSubjectPublicKeyInfo(ReadOnlySpan source) Helpers.ThrowIfAsnInvalidLength(source); ThrowIfNotSupported(); - unsafe - { - fixed (byte* pointer = source) - { - using (PointerMemoryManager manager = new(pointer, source.Length)) - { - ValueAsnReader reader = new ValueAsnReader(source, AsnEncodingRules.DER); - SubjectPublicKeyInfoAsn.Decode(ref reader, manager.Memory, out SubjectPublicKeyInfoAsn spki); - - MLDsaAlgorithm algorithm = GetAlgorithmIdentifier(ref spki.Algorithm); - ReadOnlySpan publicKey = spki.SubjectPublicKey.Span; + KeyFormatHelper.ReadSubjectPublicKeyInfo(KnownOids, source, SubjectPublicKeyReader, out int read, out MLDsa mldsa); + Debug.Assert(read == source.Length); + return mldsa; - if (publicKey.Length != algorithm.PublicKeySizeInBytes) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); - } + static void SubjectPublicKeyReader(ReadOnlySpan key, in ValueAlgorithmIdentifierAsn identifier, out MLDsa mldsa) + { + MLDsaAlgorithm algorithm = GetAlgorithmIdentifier(in identifier); - return MLDsaImplementation.ImportPublicKey(algorithm, spki.SubjectPublicKey.Span); - } + if (key.Length != algorithm.PublicKeySizeInBytes) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } + + mldsa = MLDsaImplementation.ImportPublicKey(algorithm, key); } } @@ -2208,42 +2202,42 @@ private TResult ExportPkcs8PrivateKeyCallback(ExportPkcs8PrivateKeyFunc } private static void MLDsaKeyReader( - ReadOnlyMemory privateKeyContents, - in AlgorithmIdentifierAsn algorithmIdentifier, + ReadOnlySpan privateKeyContents, + in ValueAlgorithmIdentifierAsn algorithmIdentifier, out MLDsa dsa) { MLDsaAlgorithm algorithm = GetAlgorithmIdentifier(in algorithmIdentifier); - MLDsaPrivateKeyAsn dsaKey = MLDsaPrivateKeyAsn.Decode(privateKeyContents, AsnEncodingRules.BER); + ValueMLDsaPrivateKeyAsn.Decode(privateKeyContents, AsnEncodingRules.BER, out ValueMLDsaPrivateKeyAsn dsaKey); - if (dsaKey.Seed is ReadOnlyMemory seed) + if (dsaKey.HasSeed) { - if (seed.Length != algorithm.PrivateSeedSizeInBytes) + if (dsaKey.Seed.Length != algorithm.PrivateSeedSizeInBytes) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - dsa = MLDsaImplementation.ImportMLDsaPrivateSeed(algorithm, seed.Span); + dsa = MLDsaImplementation.ImportMLDsaPrivateSeed(algorithm, dsaKey.Seed); } - else if (dsaKey.ExpandedKey is ReadOnlyMemory expandedKey) + else if (dsaKey.HasExpandedKey) { - if (expandedKey.Length != algorithm.PrivateKeySizeInBytes) + if (dsaKey.ExpandedKey.Length != algorithm.PrivateKeySizeInBytes) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - dsa = MLDsaImplementation.ImportPrivateKey(algorithm, expandedKey.Span); + dsa = MLDsaImplementation.ImportPrivateKey(algorithm, dsaKey.ExpandedKey); } - else if (dsaKey.Both is MLDsaPrivateKeyBothAsn both) + else if (dsaKey.HasBoth) { int privateKeySize = algorithm.PrivateKeySizeInBytes; - if (both.Seed.Length != algorithm.PrivateSeedSizeInBytes || - both.ExpandedKey.Length != privateKeySize) + if (dsaKey.Both.Seed.Length != algorithm.PrivateSeedSizeInBytes || + dsaKey.Both.ExpandedKey.Length != privateKeySize) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - MLDsa key = MLDsaImplementation.ImportMLDsaPrivateSeed(algorithm, both.Seed.Span); + MLDsa key = MLDsaImplementation.ImportMLDsaPrivateSeed(algorithm, dsaKey.Both.Seed); byte[] rent = CryptoPool.Rent(privateKeySize); Span buffer = rent.AsSpan(0, privateKeySize); @@ -2251,7 +2245,7 @@ private static void MLDsaKeyReader( { key.ExportMLDsaPrivateKey(buffer); - if (CryptographicOperations.FixedTimeEquals(buffer, both.ExpandedKey.Span)) + if (CryptographicOperations.FixedTimeEquals(buffer, dsaKey.Both.ExpandedKey)) { dsa = key; } @@ -2276,17 +2270,15 @@ private static void MLDsaKeyReader( } } - private static MLDsaAlgorithm GetAlgorithmIdentifier(ref readonly AlgorithmIdentifierAsn identifier) + private static MLDsaAlgorithm GetAlgorithmIdentifier(ref readonly ValueAlgorithmIdentifierAsn identifier) { MLDsaAlgorithm algorithm = MLDsaAlgorithm.GetMLDsaAlgorithmFromOid(identifier.Algorithm) ?? throw new CryptographicException( SR.Format(SR.Cryptography_UnknownAlgorithmIdentifier, identifier.Algorithm)); - if (identifier.Parameters.HasValue) + if (identifier.HasParameters) { - AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); - identifier.Encode(writer); - throw Helpers.CreateAlgorithmUnknownException(writer); + throw Helpers.CreateAlgorithmUnknownException(in identifier); } return algorithm; diff --git a/src/libraries/Common/src/System/Security/Cryptography/MLDsaCng.Windows.cs b/src/libraries/Common/src/System/Security/Cryptography/MLDsaCng.Windows.cs index dee5e6b7c7db3a..a2ec3aaf4dab37 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/MLDsaCng.Windows.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/MLDsaCng.Windows.cs @@ -123,16 +123,28 @@ protected override void ExportMLDsaPrivateSeedCore(Span destination) ExportKeyWithEncryptedOnlyExport( static (ref readonly mldsaPrivateKeyAsn, algorithm, destination) => { - ReadOnlyMemory? seed = mldsaPrivateKeyAsn.Seed ?? mldsaPrivateKeyAsn.Both?.Seed; + ReadOnlySpan seedValue = default; + bool hasSeed = false; - if (seed is ReadOnlyMemory seedValue) + if (mldsaPrivateKeyAsn.HasSeed) + { + hasSeed = true; + seedValue = mldsaPrivateKeyAsn.Seed; + } + else if (mldsaPrivateKeyAsn.HasBoth) + { + hasSeed = true; + seedValue = mldsaPrivateKeyAsn.Both.Seed; + } + + if (hasSeed) { if (seedValue.Length != algorithm.PrivateSeedSizeInBytes) { throw new CryptographicException(SR.Argument_PrivateSeedWrongSizeForAlgorithm); } - seedValue.Span.CopyTo(destination); + seedValue.CopyTo(destination); return; } @@ -156,30 +168,41 @@ protected override void ExportMLDsaPrivateKeyCore(Span destination) { ExportKeyWithEncryptedOnlyExport(static (ref readonly mldsaPrivateKeyAsn, algorithm, destination) => { - ReadOnlyMemory? expandedKey = mldsaPrivateKeyAsn.ExpandedKey ?? mldsaPrivateKeyAsn.Both?.ExpandedKey; + ReadOnlySpan expandedKeyValue = default; + bool hasExpandedKey = false; - if (expandedKey is ReadOnlyMemory expandedKeyValue) + if (mldsaPrivateKeyAsn.HasExpandedKey) + { + hasExpandedKey = true; + expandedKeyValue = mldsaPrivateKeyAsn.ExpandedKey; + } + else if (mldsaPrivateKeyAsn.HasBoth) + { + hasExpandedKey = true; + expandedKeyValue = mldsaPrivateKeyAsn.Both.ExpandedKey; + } + + if (hasExpandedKey) { if (expandedKeyValue.Length != algorithm.PrivateKeySizeInBytes) { throw new CryptographicException(SR.Argument_PrivateKeyWrongSizeForAlgorithm); } - expandedKeyValue.Span.CopyTo(destination); + expandedKeyValue.CopyTo(destination); return; } - // If PKCS#8 only has seed, then we can calculate the private key - ReadOnlyMemory? seed = mldsaPrivateKeyAsn.Seed; - - if (seed is ReadOnlyMemory seedValue) + if (mldsaPrivateKeyAsn.HasSeed) { + ReadOnlySpan seedValue = mldsaPrivateKeyAsn.Seed; + if (seedValue.Length != algorithm.PrivateSeedSizeInBytes) { throw new CryptographicException(SR.Argument_PrivateSeedWrongSizeForAlgorithm); } - using (MLDsa cloned = MLDsaImplementation.ImportSeed(algorithm, seedValue.Span)) + using (MLDsa cloned = MLDsaImplementation.ImportSeed(algorithm, seedValue)) { cloned.ExportMLDsaPrivateKey(destination); return; @@ -432,10 +455,7 @@ protected override void Dispose(bool disposing) base.Dispose(disposing); } - private void ExportKey( - CngKeyBlobFormat blobFormat, - int expectedKeySize, - Span destination) + private void ExportKey(CngKeyBlobFormat blobFormat, int expectedKeySize, Span destination) { byte[] blob = _key.Export(blobFormat); @@ -462,7 +482,7 @@ private void ExportKey( } private delegate void KeySelectorFunc( - ref readonly MLDsaPrivateKeyAsn mldsaPrivateKeyAsn, + ref readonly ValueMLDsaPrivateKeyAsn mldsaPrivateKeyAsn, MLDsaAlgorithm algorithm, Span destination); @@ -473,12 +493,12 @@ private void ExportKeyWithEncryptedOnlyExport(KeySelectorFunc keySelector, MLDsa try { - ReadOnlyMemory privateKey = KeyFormatHelper.ReadPkcs8(KnownOids, pkcs8.AsMemory(), out _); - MLDsaPrivateKeyAsn mldsaPrivateKeyAsn; + ReadOnlySpan privateKey = KeyFormatHelper.ReadPkcs8(KnownOids, pkcs8.AsSpan(), out _); + scoped ValueMLDsaPrivateKeyAsn mldsaPrivateKeyAsn; try { - mldsaPrivateKeyAsn = MLDsaPrivateKeyAsn.Decode(privateKey, AsnEncodingRules.BER); + ValueMLDsaPrivateKeyAsn.Decode(privateKey, AsnEncodingRules.BER, out mldsaPrivateKeyAsn); } catch (AsnContentException e) { diff --git a/src/libraries/Common/src/System/Security/Cryptography/MLDsaPkcs8.cs b/src/libraries/Common/src/System/Security/Cryptography/MLDsaPkcs8.cs index 9851b4408c0266..3513139f6474cf 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/MLDsaPkcs8.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/MLDsaPkcs8.cs @@ -15,13 +15,12 @@ internal static bool TryExportPkcs8PrivateKey( Span destination, out int bytesWritten) { - AlgorithmIdentifierAsn algorithmIdentifier = new() + ValueAlgorithmIdentifierAsn algorithmIdentifier = new() { Algorithm = dsa.Algorithm.Oid, - Parameters = default(ReadOnlyMemory?), }; - MLDsaPrivateKeyAsn privateKeyAsn = default; + ValueMLDsaPrivateKeyAsn privateKeyAsn = default; byte[]? rented = null; int written = 0; @@ -31,8 +30,8 @@ internal static bool TryExportPkcs8PrivateKey( { int seedSize = dsa.Algorithm.PrivateSeedSizeInBytes; rented = CryptoPool.Rent(seedSize); - Memory buffer = rented.AsMemory(0, seedSize); - dsa.ExportMLDsaPrivateSeed(buffer.Span); + Span buffer = rented.AsSpan(0, seedSize); + dsa.ExportMLDsaPrivateSeed(buffer); written = buffer.Length; privateKeyAsn.Seed = buffer; } @@ -40,8 +39,8 @@ internal static bool TryExportPkcs8PrivateKey( { int privateKeySize = dsa.Algorithm.PrivateKeySizeInBytes; rented = CryptoPool.Rent(privateKeySize); - Memory buffer = rented.AsMemory(0, privateKeySize); - dsa.ExportMLDsaPrivateKey(buffer.Span); + Span buffer = rented.AsSpan(0, privateKeySize); + dsa.ExportMLDsaPrivateKey(buffer); written = buffer.Length; privateKeyAsn.ExpandedKey = buffer; } diff --git a/src/libraries/Common/src/System/Security/Cryptography/MLKem.cs b/src/libraries/Common/src/System/Security/Cryptography/MLKem.cs index 0bcf585e0ec0c6..9a7fa8b7b21552 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/MLKem.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/MLKem.cs @@ -1207,7 +1207,7 @@ public static MLKem ImportSubjectPublicKeyInfo(ReadOnlySpan source) Debug.Assert(read == source.Length); return kem; - static void SubjectPublicKeyReader(ReadOnlyMemory key, in AlgorithmIdentifierAsn identifier, out MLKem kem) + static void SubjectPublicKeyReader(ReadOnlySpan key, in ValueAlgorithmIdentifierAsn identifier, out MLKem kem) { MLKemAlgorithm algorithm = GetAlgorithmIdentifier(in identifier); @@ -1216,7 +1216,7 @@ static void SubjectPublicKeyReader(ReadOnlyMemory key, in AlgorithmIdentif throw new CryptographicException(SR.Argument_KemInvalidEncapsulationKeyLength); } - kem = MLKemImplementation.ImportEncapsulationKeyImpl(algorithm, key.Span); + kem = MLKemImplementation.ImportEncapsulationKeyImpl(algorithm, key); } } @@ -1704,58 +1704,56 @@ private protected static void ThrowIfNotSupported() } } - private static MLKemAlgorithm GetAlgorithmIdentifier(ref readonly AlgorithmIdentifierAsn identifier) + private static MLKemAlgorithm GetAlgorithmIdentifier(ref readonly ValueAlgorithmIdentifierAsn identifier) { MLKemAlgorithm? algorithm = MLKemAlgorithm.FromOid(identifier.Algorithm); Debug.Assert(algorithm is not null, "Algorithm identifier should have been pre-validated by KeyFormatHelper."); - if (identifier.Parameters.HasValue) + if (identifier.HasParameters) { - AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); - identifier.Encode(writer); - throw Helpers.CreateAlgorithmUnknownException(writer); + throw Helpers.CreateAlgorithmUnknownException(in identifier); } return algorithm; } private static void MLKemKeyReader( - ReadOnlyMemory privateKeyContents, - in AlgorithmIdentifierAsn algorithmIdentifier, + ReadOnlySpan privateKeyContents, + in ValueAlgorithmIdentifierAsn algorithmIdentifier, out MLKem kem) { MLKemAlgorithm algorithm = GetAlgorithmIdentifier(in algorithmIdentifier); - MLKemPrivateKeyAsn kemKey = MLKemPrivateKeyAsn.Decode(privateKeyContents, AsnEncodingRules.BER); + ValueMLKemPrivateKeyAsn.Decode(privateKeyContents, AsnEncodingRules.BER, out ValueMLKemPrivateKeyAsn kemKey); - if (kemKey.Seed is ReadOnlyMemory seed) + if (kemKey.HasSeed) { - if (seed.Length != algorithm.PrivateSeedSizeInBytes) + if (kemKey.Seed.Length != algorithm.PrivateSeedSizeInBytes) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - kem = MLKemImplementation.ImportPrivateSeedImpl(algorithm, seed.Span); + kem = MLKemImplementation.ImportPrivateSeedImpl(algorithm, kemKey.Seed); } - else if (kemKey.ExpandedKey is ReadOnlyMemory expandedKey) + else if (kemKey.HasExpandedKey) { - if (expandedKey.Length != algorithm.DecapsulationKeySizeInBytes) + if (kemKey.ExpandedKey.Length != algorithm.DecapsulationKeySizeInBytes) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - kem = MLKemImplementation.ImportDecapsulationKeyImpl(algorithm, expandedKey.Span); + kem = MLKemImplementation.ImportDecapsulationKeyImpl(algorithm, kemKey.ExpandedKey); } - else if (kemKey.Both is MLKemPrivateKeyBothAsn both) + else if (kemKey.HasBoth) { int decapsulationKeySize = algorithm.DecapsulationKeySizeInBytes; - if (both.Seed.Length != algorithm.PrivateSeedSizeInBytes || - both.ExpandedKey.Length != decapsulationKeySize) + if (kemKey.Both.Seed.Length != algorithm.PrivateSeedSizeInBytes || + kemKey.Both.ExpandedKey.Length != decapsulationKeySize) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - MLKem key = MLKemImplementation.ImportPrivateSeedImpl(algorithm, both.Seed.Span); + MLKem key = MLKemImplementation.ImportPrivateSeedImpl(algorithm, kemKey.Both.Seed); byte[] rent = CryptoPool.Rent(decapsulationKeySize); Span buffer = rent.AsSpan(0, decapsulationKeySize); @@ -1763,7 +1761,7 @@ private static void MLKemKeyReader( { key.ExportDecapsulationKey(buffer); - if (CryptographicOperations.FixedTimeEquals(buffer, both.ExpandedKey.Span)) + if (CryptographicOperations.FixedTimeEquals(buffer, kemKey.Both.ExpandedKey)) { kem = key; } diff --git a/src/libraries/Common/src/System/Security/Cryptography/MLKemPkcs8.cs b/src/libraries/Common/src/System/Security/Cryptography/MLKemPkcs8.cs index 6a3fef4b221b90..4e61221c89afb8 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/MLKemPkcs8.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/MLKemPkcs8.cs @@ -15,13 +15,12 @@ internal static bool TryExportPkcs8PrivateKey( Span destination, out int bytesWritten) { - AlgorithmIdentifierAsn algorithmIdentifier = new() + ValueAlgorithmIdentifierAsn algorithmIdentifier = new() { Algorithm = kem.Algorithm.Oid, - Parameters = default(ReadOnlyMemory?), }; - MLKemPrivateKeyAsn privateKeyAsn = default; + ValueMLKemPrivateKeyAsn privateKeyAsn = default; byte[]? rented = null; int written = 0; @@ -31,8 +30,8 @@ internal static bool TryExportPkcs8PrivateKey( { int seedSize = kem.Algorithm.PrivateSeedSizeInBytes; rented = CryptoPool.Rent(seedSize); - Memory buffer = rented.AsMemory(0, seedSize); - kem.ExportPrivateSeed(buffer.Span); + Span buffer = rented.AsSpan(0, seedSize); + kem.ExportPrivateSeed(buffer); written = buffer.Length; privateKeyAsn.Seed = buffer; } @@ -40,8 +39,8 @@ internal static bool TryExportPkcs8PrivateKey( { int decapsulationKeySize = kem.Algorithm.DecapsulationKeySizeInBytes; rented = CryptoPool.Rent(decapsulationKeySize); - Memory buffer = rented.AsMemory(0, decapsulationKeySize); - kem.ExportDecapsulationKey(buffer.Span); + Span buffer = rented.AsSpan(0, decapsulationKeySize); + kem.ExportDecapsulationKey(buffer); written = buffer.Length; privateKeyAsn.ExpandedKey = buffer; } diff --git a/src/libraries/Common/src/System/Security/Cryptography/PasswordBasedEncryption.cs b/src/libraries/Common/src/System/Security/Cryptography/PasswordBasedEncryption.cs index cb9db0df3ab661..0ede657ed960f5 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/PasswordBasedEncryption.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/PasswordBasedEncryption.cs @@ -14,6 +14,18 @@ namespace System.Security.Cryptography { internal static class PasswordBasedEncryption { + private readonly ref struct OptionalReadOnlySpan + { + public OptionalReadOnlySpan(ReadOnlySpan value, bool hasValue) + { + Value = value; + HasValue = hasValue; + } + + public ReadOnlySpan Value { get; } + public bool HasValue { get; } + } + internal const int IterationLimit = 600000; private static CryptographicException AlgorithmKdfRequiresChars(string algId) @@ -64,10 +76,25 @@ internal static void ValidatePbeParameters( encryptionAlgorithm.ToString()); } + internal static unsafe int Decrypt( + in AlgorithmIdentifierAsn algorithmIdentifier, + ReadOnlySpan password, + ReadOnlySpan passwordBytes, + ReadOnlySpan encryptedData, + Span destination) + { + return Decrypt( + algorithmIdentifier.AsValueAlgorithmIdentifierAsn(), + password, + passwordBytes, + encryptedData, + destination); + } + [SuppressMessage("Microsoft.Security", "CA5350", Justification = "3DES used when specified by the input data")] [SuppressMessage("Microsoft.Security", "CA5351", Justification = "DES used when specified by the input data")] internal static unsafe int Decrypt( - in AlgorithmIdentifierAsn algorithmIdentifier, + in ValueAlgorithmIdentifierAsn algorithmIdentifier, ReadOnlySpan password, ReadOnlySpan passwordBytes, ReadOnlySpan encryptedData, @@ -134,7 +161,7 @@ internal static unsafe int Decrypt( break; case Oids.PasswordBasedEncryptionScheme2: return Pbes2Decrypt( - algorithmIdentifier.Parameters, + new OptionalReadOnlySpan(algorithmIdentifier.Parameters, algorithmIdentifier.HasParameters), password, passwordBytes, encryptedData, @@ -207,7 +234,7 @@ internal static unsafe int Decrypt( try { return Pbes1Decrypt( - algorithmIdentifier.Parameters, + new OptionalReadOnlySpan(algorithmIdentifier.Parameters, algorithmIdentifier.HasParameters), effectivePasswordBytes, hasher, cipher, @@ -448,7 +475,7 @@ internal static unsafe int Encrypt( } private static unsafe int Pbes2Decrypt( - ReadOnlyMemory? algorithmParameters, + OptionalReadOnlySpan algorithmParameters, ReadOnlySpan password, ReadOnlySpan passwordBytes, ReadOnlySpan encryptedData, @@ -508,7 +535,7 @@ private static unsafe int Pbes2Decrypt( } private static unsafe int Pbes2Decrypt( - ReadOnlyMemory? algorithmParameters, + OptionalReadOnlySpan algorithmParameters, ReadOnlySpan password, ReadOnlySpan encryptedData, Span destination) @@ -518,7 +545,7 @@ private static unsafe int Pbes2Decrypt( throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - PBES2Params pbes2Params = PBES2Params.Decode(algorithmParameters.Value, AsnEncodingRules.BER); + ValuePBES2Params.Decode(algorithmParameters.Value, AsnEncodingRules.BER, out ValuePBES2Params pbes2Params); if (pbes2Params.KeyDerivationFunc.Algorithm != Oids.Pbkdf2) { @@ -529,7 +556,10 @@ private static unsafe int Pbes2Decrypt( } Rfc2898DeriveBytes pbkdf2 = - OpenPbkdf2(password, pbes2Params.KeyDerivationFunc.Parameters, out int? requestedKeyLength); + OpenPbkdf2( + password, + new OptionalReadOnlySpan(pbes2Params.KeyDerivationFunc.Parameters, pbes2Params.KeyDerivationFunc.HasParameters), + out int? requestedKeyLength); using (pbkdf2) { @@ -563,7 +593,7 @@ private static unsafe int Pbes2Decrypt( [SuppressMessage("Microsoft.Security", "CA5350", Justification = "3DES used when specified by the input data")] [SuppressMessage("Microsoft.Security", "CA5351", Justification = "DES used when specified by the input data")] private static SymmetricAlgorithm OpenCipher( - AlgorithmIdentifierAsn encryptionScheme, + in ValueAlgorithmIdentifierAsn encryptionScheme, int? requestedKeyLength, ref Span iv) { @@ -606,7 +636,10 @@ private static SymmetricAlgorithm OpenCipher( // The parameters field ... shall have type OCTET STRING (SIZE(16)) // specifying the initialization vector ... - ReadIvParameter(encryptionScheme.Parameters, 16, ref iv); + ReadIvParameter( + new OptionalReadOnlySpan(encryptionScheme.Parameters, encryptionScheme.HasParameters), + 16, + ref iv); Aes aes = Aes.Create(); aes.KeySize = correctKeySize * 8; @@ -625,7 +658,10 @@ private static SymmetricAlgorithm OpenCipher( // The parameters field associated with this OID ... shall have type // OCTET STRING (SIZE(8)) specifying the initialization vector ... - ReadIvParameter(encryptionScheme.Parameters, 8, ref iv); + ReadIvParameter( + new OptionalReadOnlySpan(encryptionScheme.Parameters, encryptionScheme.HasParameters), + 8, + ref iv); return TripleDES.Create(); } @@ -633,7 +669,7 @@ private static SymmetricAlgorithm OpenCipher( { // https://tools.ietf.org/html/rfc8018#appendix-B.2.3 - if (encryptionScheme.Parameters == null) + if (!encryptionScheme.HasParameters) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } @@ -645,9 +681,10 @@ private static SymmetricAlgorithm OpenCipher( throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - Rc2CbcParameters rc2Parameters = Rc2CbcParameters.Decode( - encryptionScheme.Parameters.Value, - AsnEncodingRules.BER); + ValueRc2CbcParameters.Decode( + encryptionScheme.Parameters, + AsnEncodingRules.BER, + out ValueRc2CbcParameters rc2Parameters); // iv is the eight-octet initialization vector if (rc2Parameters.Iv.Length != 8) @@ -659,7 +696,7 @@ private static SymmetricAlgorithm OpenCipher( rc2.KeySize = requestedKeyLength.Value * 8; rc2.EffectiveKeySize = rc2Parameters.GetEffectiveKeyBits(); - rc2Parameters.Iv.Span.CopyTo(iv); + rc2Parameters.Iv.CopyTo(iv); iv = iv.Slice(0, rc2Parameters.Iv.Length); return rc2; } @@ -676,7 +713,10 @@ private static SymmetricAlgorithm OpenCipher( // The parameters field associated with this OID ... shall have type // OCTET STRING (SIZE(8)) specifying the initialization vector ... - ReadIvParameter(encryptionScheme.Parameters, 8, ref iv); + ReadIvParameter( + new OptionalReadOnlySpan(encryptionScheme.Parameters, encryptionScheme.HasParameters), + 8, + ref iv); return DES.Create(); } @@ -684,18 +724,18 @@ private static SymmetricAlgorithm OpenCipher( } private static void ReadIvParameter( - ReadOnlyMemory? encryptionSchemeParameters, + OptionalReadOnlySpan encryptionSchemeParameters, int length, ref Span iv) { - if (encryptionSchemeParameters == null) + if (!encryptionSchemeParameters.HasValue) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } try { - ReadOnlySpan source = encryptionSchemeParameters.Value.Span; + ReadOnlySpan source = encryptionSchemeParameters.Value; bool gotIv = AsnDecoder.TryReadOctetString( source, @@ -720,7 +760,7 @@ private static void ReadIvParameter( [SuppressMessage("Microsoft.Security", "CA5379", Justification = "SHA1 used if specified by argument")] private static unsafe Rfc2898DeriveBytes OpenPbkdf2( ReadOnlySpan password, - ReadOnlyMemory? parameters, + OptionalReadOnlySpan parameters, out int? requestedKeyLength) { if (!parameters.HasValue) @@ -728,19 +768,19 @@ private static unsafe Rfc2898DeriveBytes OpenPbkdf2( throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - Pbkdf2Params pbkdf2Params = Pbkdf2Params.Decode(parameters.Value, AsnEncodingRules.BER); + ValuePbkdf2Params.Decode(parameters.Value, AsnEncodingRules.BER, out ValuePbkdf2Params pbkdf2Params); // No OtherSource is defined in RFC 2898 or RFC 8018, so whatever // algorithm was requested isn't one we know. - if (pbkdf2Params.Salt.OtherSource != null) + if (pbkdf2Params.Salt.HasOtherSource) { throw new CryptographicException( SR.Format( SR.Cryptography_UnknownAlgorithmIdentifier, - pbkdf2Params.Salt.OtherSource.Value.Algorithm)); + pbkdf2Params.Salt.OtherSource.Algorithm)); } - if (pbkdf2Params.Salt.Specified == null) + if (!pbkdf2Params.Salt.HasSpecified) { Debug.Fail($"No Specified Salt value is present, indicating a new choice was unhandled"); throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); @@ -767,16 +807,16 @@ private static unsafe Rfc2898DeriveBytes OpenPbkdf2( } int iterationCount = NormalizeIterationCount(pbkdf2Params.IterationCount); - ReadOnlyMemory saltMemory = pbkdf2Params.Salt.Specified.Value; + ReadOnlySpan saltSpan = pbkdf2Params.Salt.Specified; byte[] tmpPassword = new byte[password.Length]; - byte[] tmpSalt = new byte[saltMemory.Length]; + byte[] tmpSalt = new byte[saltSpan.Length]; fixed (byte* tmpPasswordPtr = tmpPassword) fixed (byte* tmpSaltPtr = tmpSalt) { password.CopyTo(tmpPassword); - saltMemory.CopyTo(tmpSalt); + saltSpan.CopyTo(tmpSalt); try { @@ -802,7 +842,7 @@ private static unsafe Rfc2898DeriveBytes OpenPbkdf2( } private static int Pbes1Decrypt( - ReadOnlyMemory? algorithmParameters, + OptionalReadOnlySpan algorithmParameters, ReadOnlySpan password, IncrementalHash hasher, SymmetricAlgorithm cipher, @@ -817,7 +857,7 @@ private static int Pbes1Decrypt( throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - PBEParameter pbeParameters = PBEParameter.Decode(algorithmParameters.Value, AsnEncodingRules.BER); + ValuePBEParameter.Decode(algorithmParameters.Value, AsnEncodingRules.BER, out ValuePBEParameter pbeParameters); if (pbeParameters.Salt.Length != 8) { @@ -836,7 +876,7 @@ private static int Pbes1Decrypt( try { - Pbkdf1(hasher, password, pbeParameters.Salt.Span, iterationCount, dk); + Pbkdf1(hasher, password, pbeParameters.Salt, iterationCount, dk); // 3. Separate the derived key DK into an encryption key K consisting of the // first eight octets of DK and an initialization vector IV consisting of the @@ -854,7 +894,7 @@ private static int Pbes1Decrypt( } private static unsafe int Pkcs12PbeDecrypt( - AlgorithmIdentifierAsn algorithmIdentifier, + in ValueAlgorithmIdentifierAsn algorithmIdentifier, ReadOnlySpan password, HashAlgorithmName hashAlgorithm, SymmetricAlgorithm cipher, @@ -863,7 +903,7 @@ private static unsafe int Pkcs12PbeDecrypt( { // https://tools.ietf.org/html/rfc7292#appendix-C - if (!algorithmIdentifier.Parameters.HasValue) + if (!algorithmIdentifier.HasParameters) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } @@ -878,14 +918,15 @@ private static unsafe int Pkcs12PbeDecrypt( throw new CryptographicException(); } - PBEParameter pbeParameters = PBEParameter.Decode( - algorithmIdentifier.Parameters.Value, - AsnEncodingRules.BER); + ValuePBEParameter.Decode( + algorithmIdentifier.Parameters, + AsnEncodingRules.BER, + out ValuePBEParameter pbeParameters); int iterationCount = NormalizeIterationCount(pbeParameters.IterationCount, IterationLimit); Span iv = stackalloc byte[cipher.BlockSize / 8]; Span key = stackalloc byte[cipher.KeySize / 8]; - ReadOnlySpan saltSpan = pbeParameters.Salt.Span; + ReadOnlySpan saltSpan = pbeParameters.Salt; try { diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs index 1d1c742609d93f..6c0a8da998dc42 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAAndroid.cs @@ -400,58 +400,53 @@ public override void ImportParameters(RSAParameters parameters) SetKeySizeFromHandle(key); } - public override unsafe void ImportRSAPublicKey(ReadOnlySpan source, out int bytesRead) + public override void ImportRSAPublicKey(ReadOnlySpan source, out int bytesRead) { ThrowIfDisposed(); - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) + ReadOnlySpan subjectPublicKey; + + try + { + ValueAsnReader reader = new ValueAsnReader(source, AsnEncodingRules.BER); + subjectPublicKey = reader.PeekEncodedValue(); + } + catch (AsnContentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + + // Decoding the key on Android requires the encoded SubjectPublicKeyInfo, + // not just the SubjectPublicKey, so we construct one. + ValueSubjectPublicKeyInfoAsn spki = new ValueSubjectPublicKeyInfoAsn { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) + Algorithm = new ValueAlgorithmIdentifierAsn { - ReadOnlyMemory subjectPublicKey; - try - { - AsnReader reader = new AsnReader(manager.Memory, AsnEncodingRules.BER); - subjectPublicKey = reader.PeekEncodedValue(); - } - catch (AsnContentException e) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); - } + Algorithm = Oids.Rsa, + Parameters = AlgorithmIdentifierAsn.ExplicitDerNull.Span, + }, + SubjectPublicKey = subjectPublicKey, + }; - // Decoding the key on Android requires the encoded SubjectPublicKeyInfo, - // not just the SubjectPublicKey, so we construct one. - SubjectPublicKeyInfoAsn spki = new SubjectPublicKeyInfoAsn - { - Algorithm = new AlgorithmIdentifierAsn - { - Algorithm = Oids.Rsa, - Parameters = AlgorithmIdentifierAsn.ExplicitDerNull, - }, - SubjectPublicKey = subjectPublicKey, - }; - - AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); - spki.Encode(writer); - - SafeRsaHandle key = writer.Encode(static (encoded) => - { - return Interop.AndroidCrypto.DecodeRsaSubjectPublicKeyInfo(encoded); - }); + AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); + spki.Encode(writer); - if (key is null || key.IsInvalid) - { - key?.Dispose(); - throw new CryptographicException(); - } - - FreeKey(); - _key = new Lazy(key); - SetKeySizeFromHandle(key); + SafeRsaHandle key = writer.Encode(static (encoded) => + { + return Interop.AndroidCrypto.DecodeRsaSubjectPublicKeyInfo(encoded); + }); - bytesRead = subjectPublicKey.Length; - } + if (key is null || key.IsInvalid) + { + key?.Dispose(); + throw new CryptographicException(); } + + FreeKey(); + _key = new Lazy(key); + SetKeySizeFromHandle(key); + + bytesRead = subjectPublicKey.Length; } public override void ImportEncryptedPkcs8PrivateKey( diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.cs index beba3ef856f373..426c9f73dcf5d5 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.cs @@ -104,7 +104,7 @@ public override RSAParameters ExportParameters(bool includePrivateParameters) if (sequenceReader.PeekTag().Equals(Asn1Tag.Integer)) { - AlgorithmIdentifierAsn ignored = default; + ValueAlgorithmIdentifierAsn ignored = default; RSAKeyFormatHelper.ReadRsaPublicKey(keyBlob, ignored, out key); } else @@ -119,7 +119,7 @@ public override RSAParameters ExportParameters(bool includePrivateParameters) } else { - AlgorithmIdentifierAsn ignored = default; + ValueAlgorithmIdentifierAsn ignored = default; RSAKeyFormatHelper.FromPkcs1PrivateKey( keyBlob, ignored, @@ -161,24 +161,18 @@ public override unsafe void ImportRSAPublicKey(ReadOnlySpan source, out in { ThrowIfDisposed(); - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - // Validate the DER value and get the number of bytes. - RSAKeyFormatHelper.ReadRsaPublicKey( - manager.Memory, - out int localRead); - - SafeSecKeyRefHandle publicKey = Interop.AppleCrypto.CreateDataKey( - source.Slice(0, localRead), - Interop.AppleCrypto.PAL_KeyAlgorithm.RSA, - isPublic: true); - SetKey(SecKeyPair.PublicOnly(publicKey)); - - bytesRead = localRead; - } - } + // Validate the DER value and get the number of bytes. + RSAKeyFormatHelper.ReadRsaPublicKey( + source, + out int localRead); + + SafeSecKeyRefHandle publicKey = Interop.AppleCrypto.CreateDataKey( + source.Slice(0, localRead), + Interop.AppleCrypto.PAL_KeyAlgorithm.RSA, + isPublic: true); + SetKey(SecKeyPair.PublicOnly(publicKey)); + + bytesRead = localRead; } public override void ImportEncryptedPkcs8PrivateKey( diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.macOS.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.macOS.cs index 2fbebb5a7d4495..6c3810da4d2def 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.macOS.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAAppleCrypto.macOS.cs @@ -44,7 +44,7 @@ private static RSAParameters ExportParametersFromLegacyKey(SecKeyPair keys, bool if (sequenceReader.PeekTag().Equals(Asn1Tag.Integer)) { - AlgorithmIdentifierAsn ignored = default; + ValueAlgorithmIdentifierAsn ignored = default; RSAKeyFormatHelper.ReadRsaPublicKey(keyBlob, ignored, out key); } else diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.Pkcs1.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.Pkcs1.cs index 016082439bc35c..693911e3fe390f 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.Pkcs1.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.Pkcs1.cs @@ -12,26 +12,12 @@ internal static partial class RSAKeyFormatHelper { internal delegate TRet RSAParametersCallback(RSAParameters parameters); - internal static unsafe TRet FromPkcs1PrivateKey( - ReadOnlySpan keyData, - RSAParametersCallback parametersReader, - bool pinAndClearParameters = true) - { - fixed (byte* ptr = &MemoryMarshal.GetReference(keyData)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, keyData.Length)) - { - return FromPkcs1PrivateKey(manager.Memory, parametersReader, pinAndClearParameters); - } - } - } - internal static TRet FromPkcs1PrivateKey( - ReadOnlyMemory keyData, + ReadOnlySpan keyData, RSAParametersCallback parametersReader, bool pinAndClearParameters = true) { - RSAPrivateKeyAsn key = RSAPrivateKeyAsn.Decode(keyData, AsnEncodingRules.BER); + ValueRSAPrivateKeyAsn.Decode(keyData, AsnEncodingRules.BER, out ValueRSAPrivateKeyAsn key); const int MaxSupportedVersion = 0; @@ -70,15 +56,15 @@ internal static TRet FromPkcs1PrivateKey( using (PinAndClear.Track(parameters.DQ)) using (PinAndClear.Track(parameters.InverseQ)) { - return ExtractParametersWithCallback(parametersReader, ref key, ref parameters); + return ExtractParametersWithCallback(parametersReader, key, ref parameters); } } else { - return ExtractParametersWithCallback(parametersReader, ref key, ref parameters); + return ExtractParametersWithCallback(parametersReader, key, ref parameters); } - static TRet ExtractParametersWithCallback(RSAParametersCallback parametersReader, ref RSAPrivateKeyAsn key, ref RSAParameters parameters) + static TRet ExtractParametersWithCallback(RSAParametersCallback parametersReader, in ValueRSAPrivateKeyAsn key, ref RSAParameters parameters) { key.PrivateExponent.ToUnsignedIntegerBytes(parameters.D); key.Prime1.ToUnsignedIntegerBytes(parameters.P); @@ -91,22 +77,11 @@ static TRet ExtractParametersWithCallback(RSAParametersCallback parameters } } - internal static unsafe TRet FromPkcs1PublicKey( + internal static TRet FromPkcs1PublicKey( ReadOnlySpan keyData, RSAParametersCallback parametersReader) { - fixed (byte* ptr = &MemoryMarshal.GetReference(keyData)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, keyData.Length)) - { - return FromPkcs1PublicKey(manager.Memory, parametersReader); - } - } - } - - internal static TRet FromPkcs1PublicKey(ReadOnlyMemory keyData, RSAParametersCallback parametersReader) - { - RSAPublicKeyAsn key = RSAPublicKeyAsn.Decode(keyData, AsnEncodingRules.BER); + ValueRSAPublicKeyAsn.Decode(keyData, AsnEncodingRules.BER, out ValueRSAPublicKeyAsn key); RSAParameters parameters = new RSAParameters { diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs index 0342133f8dcab3..b50e5a2a4b1420 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAKeyFormatHelper.cs @@ -16,8 +16,8 @@ internal static partial class RSAKeyFormatHelper }; internal static void FromPkcs1PrivateKey( - ReadOnlyMemory keyData, - in AlgorithmIdentifierAsn algId, + ReadOnlySpan keyData, + in ValueAlgorithmIdentifierAsn algId, out RSAParameters ret) { if (!algId.HasNullEquivalentParameters()) @@ -29,24 +29,22 @@ internal static void FromPkcs1PrivateKey( } internal static void ReadRsaPublicKey( - ReadOnlyMemory keyData, - in AlgorithmIdentifierAsn algId, + ReadOnlySpan keyData, + in ValueAlgorithmIdentifierAsn algId, out RSAParameters ret) { ret = FromPkcs1PublicKey(keyData, rsaParameters => rsaParameters); } - internal static void ReadRsaPublicKey( - ReadOnlyMemory keyData, - out int bytesRead) + internal static void ReadRsaPublicKey(ReadOnlySpan keyData, out int bytesRead) { int read; try { - ValueAsnReader reader = new ValueAsnReader(keyData.Span, AsnEncodingRules.DER); + ValueAsnReader reader = new ValueAsnReader(keyData, AsnEncodingRules.DER); read = reader.PeekEncodedValue().Length; - RSAPublicKeyAsn.Decode(keyData, AsnEncodingRules.BER); + ValueRSAPublicKeyAsn.Decode(keyData, AsnEncodingRules.BER, out _); } catch (AsnContentException e) { @@ -69,9 +67,7 @@ internal static void ReadSubjectPublicKeyInfo( out key); } - internal static ReadOnlyMemory ReadSubjectPublicKeyInfo( - ReadOnlyMemory source, - out int bytesRead) + internal static ReadOnlySpan ReadSubjectPublicKeyInfo(ReadOnlySpan source, out int bytesRead) { return KeyFormatHelper.ReadSubjectPublicKeyInfo( s_validOids, @@ -79,51 +75,18 @@ internal static ReadOnlyMemory ReadSubjectPublicKeyInfo( out bytesRead); } - /// - /// Checks that a SubjectPublicKeyInfo represents an RSA key. - /// - /// The number of bytes read from . - internal static unsafe int CheckSubjectPublicKeyInfo(ReadOnlySpan source) + internal static ReadOnlySpan ReadPkcs8(ReadOnlySpan source, out int bytesRead) { - int bytesRead; - - fixed (byte* ptr = source) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - _ = ReadSubjectPublicKeyInfo(manager.Memory, out bytesRead); - } - } - - return bytesRead; - } - - internal static ReadOnlyMemory ReadPkcs8( - ReadOnlyMemory source, - out int bytesRead) - { - return KeyFormatHelper.ReadPkcs8( - s_validOids, - source, - out bytesRead); + return KeyFormatHelper.ReadPkcs8(s_validOids, source, out bytesRead); } /// /// Checks that a Pkcs8PrivateKeyInfo represents an RSA key. /// /// The number of bytes read from . - internal static unsafe int CheckPkcs8(ReadOnlySpan source) + internal static int CheckPkcs8(ReadOnlySpan source) { - int bytesRead; - - fixed (byte* ptr = source) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - _ = ReadPkcs8(manager.Memory, out bytesRead); - } - } - + ReadPkcs8(source, out int bytesRead); return bytesRead; } diff --git a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs index 4c69763709e631..060f002ebb527f 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/RSAOpenSsl.cs @@ -273,11 +273,11 @@ private static bool TryEncrypt( return true; } - private delegate T ExportPrivateKeyFunc(ReadOnlyMemory pkcs8, ReadOnlyMemory pkcs1); + private delegate T ExportPrivateKeyFunc(ReadOnlySpan pkcs8, ReadOnlySpan pkcs1); - private delegate ReadOnlyMemory TryExportPrivateKeySelector( - ReadOnlyMemory pkcs8, - ReadOnlyMemory pkcs1); + private delegate ReadOnlySpan TryExportPrivateKeySelector( + ReadOnlySpan pkcs8, + ReadOnlySpan pkcs1); private T ExportPrivateKey(ExportPrivateKeyFunc exporter) { @@ -288,7 +288,7 @@ private T ExportPrivateKey(ExportPrivateKeyFunc exporter) try { - ReadOnlyMemory pkcs1 = VerifyPkcs8(p8); + ReadOnlySpan pkcs1 = VerifyPkcs8(p8); return exporter(p8, pkcs1); } finally @@ -306,9 +306,9 @@ private bool TryExportPrivateKey(TryExportPrivateKeySelector selector, Span pkcs1 = VerifyPkcs8(p8); - ReadOnlyMemory selected = selector(p8, pkcs1); - return selected.Span.TryCopyToDestination(destination, out bytesWritten); + ReadOnlySpan pkcs1 = VerifyPkcs8(p8); + ReadOnlySpan selected = selector(p8, pkcs1); + return selected.TryCopyToDestination(destination, out bytesWritten); } finally { @@ -316,7 +316,7 @@ private bool TryExportPrivateKey(TryExportPrivateKeySelector selector, Span(Func, T> exporter) + private T ExportPublicKey(Func, T> exporter) { // It's entirely possible that this line will cause the key to be generated in the first place. SafeEvpPKeyHandle key = GetKey(); @@ -334,7 +334,7 @@ private T ExportPublicKey(Func, T> exporter) } private bool TryExportPublicKey( - Func, ReadOnlyMemory>? transform, + Func, ReadOnlySpan>? transform, Span destination, out int bytesWritten) { @@ -345,14 +345,14 @@ private bool TryExportPublicKey( try { - ReadOnlyMemory data = spki; + ReadOnlySpan data = spki; if (transform != null) { data = transform(data); } - return data.Span.TryCopyToDestination(destination, out bytesWritten); + return data.TryCopyToDestination(destination, out bytesWritten); } finally { @@ -385,7 +385,7 @@ public override byte[] ExportRSAPublicKey() return ExportPublicKey( static spki => { - ReadOnlyMemory pkcs1 = RSAKeyFormatHelper.ReadSubjectPublicKeyInfo(spki, out int read); + ReadOnlySpan pkcs1 = RSAKeyFormatHelper.ReadSubjectPublicKeyInfo(spki, out int read); Debug.Assert(read == spki.Length); return pkcs1.ToArray(); }); @@ -396,7 +396,7 @@ public override bool TryExportRSAPublicKey(Span destination, out int bytes return TryExportPublicKey( spki => { - ReadOnlyMemory pkcs1 = RSAKeyFormatHelper.ReadSubjectPublicKeyInfo(spki, out int read); + ReadOnlySpan pkcs1 = RSAKeyFormatHelper.ReadSubjectPublicKeyInfo(spki, out int read); Debug.Assert(read == spki.Length); return pkcs1; }, @@ -424,7 +424,7 @@ public override RSAParameters ExportParameters(bool includePrivateParameters) return ExportPrivateKey( static (pkcs8, pkcs1) => { - AlgorithmIdentifierAsn algId = default; + ValueAlgorithmIdentifierAsn algId = default; RSAParameters ret; RSAKeyFormatHelper.FromPkcs1PrivateKey(pkcs1, in algId, out ret); return ret; @@ -436,7 +436,7 @@ public override RSAParameters ExportParameters(bool includePrivateParameters) { RSAParameters ret; RSAKeyFormatHelper.ReadSubjectPublicKeyInfo( - spki.Span, + spki, out int read, out ret); @@ -515,7 +515,7 @@ private void ImportSubjectPublicKeyInfo( if (checkAlgorithm) { - read = RSAKeyFormatHelper.CheckSubjectPublicKeyInfo(source); + RSAKeyFormatHelper.ReadSubjectPublicKeyInfo(source, out read); } else { @@ -776,7 +776,7 @@ public override bool VerifyHash(ReadOnlySpan hash, ReadOnlySpan sign signature); } - private static ReadOnlyMemory VerifyPkcs8(ReadOnlyMemory pkcs8) + private static ReadOnlySpan VerifyPkcs8(ReadOnlySpan pkcs8) { // OpenSSL 1.1.1 will export RSA public keys as a PKCS#8, but this makes a broken structure. // @@ -785,9 +785,9 @@ private static ReadOnlyMemory VerifyPkcs8(ReadOnlyMemory pkcs8) try { - ReadOnlyMemory pkcs1Priv = RSAKeyFormatHelper.ReadPkcs8(pkcs8, out int read); + ReadOnlySpan pkcs1Priv = RSAKeyFormatHelper.ReadPkcs8(pkcs8, out int read); Debug.Assert(read == pkcs8.Length); - _ = RSAPrivateKeyAsn.Decode(pkcs1Priv, AsnEncodingRules.BER); + ValueRSAPrivateKeyAsn.Decode(pkcs1Priv, AsnEncodingRules.BER, out _); return pkcs1Priv; } catch (CryptographicException) diff --git a/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs b/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs index c915248b1caa9b..d8ed8f1aaaf7f0 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/SlhDsa.cs @@ -1226,7 +1226,7 @@ public static SlhDsa ImportSubjectPublicKeyInfo(ReadOnlySpan source) Debug.Assert(read == source.Length); return slhDsa; - static void SubjectPublicKeyReader(ReadOnlyMemory key, in AlgorithmIdentifierAsn identifier, out SlhDsa slhDsa) + static void SubjectPublicKeyReader(ReadOnlySpan key, in ValueAlgorithmIdentifierAsn identifier, out SlhDsa slhDsa) { SlhDsaAlgorithm algorithm = GetAlgorithmIdentifier(in identifier); @@ -1235,7 +1235,7 @@ static void SubjectPublicKeyReader(ReadOnlyMemory key, in AlgorithmIdentif throw new CryptographicException(SR.Argument_PublicKeyWrongSizeForAlgorithm); } - slhDsa = SlhDsaImplementation.ImportPublicKey(algorithm, key.Span); + slhDsa = SlhDsaImplementation.ImportPublicKey(algorithm, key); } } @@ -1288,17 +1288,16 @@ public static SlhDsa ImportPkcs8PrivateKey(ReadOnlySpan source) KeyFormatHelper.ReadPkcs8( s_knownOids, source, - (ReadOnlyMemory key, in AlgorithmIdentifierAsn algId, out SlhDsa ret) => + (ReadOnlySpan key, in ValueAlgorithmIdentifierAsn algId, out SlhDsa ret) => { SlhDsaAlgorithm info = GetAlgorithmIdentifier(in algId); - ReadOnlySpan privateKey = key.Span; - if (privateKey.Length != info.PrivateKeySizeInBytes) + if (key.Length != info.PrivateKeySizeInBytes) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - ret = ImportSlhDsaPrivateKey(info, key.Span); + ret = ImportSlhDsaPrivateKey(info, key); }, out int read, out SlhDsa slhDsa); @@ -1982,16 +1981,14 @@ private TResult ExportPkcs8PrivateKeyCallback(ExportPkcs8PrivateKeyFunc } } - private static SlhDsaAlgorithm GetAlgorithmIdentifier(ref readonly AlgorithmIdentifierAsn identifier) + private static SlhDsaAlgorithm GetAlgorithmIdentifier(ref readonly ValueAlgorithmIdentifierAsn identifier) { SlhDsaAlgorithm? algorithm = SlhDsaAlgorithm.GetAlgorithmFromOid(identifier.Algorithm); Debug.Assert(algorithm is not null, "Algorithm identifier should have been pre-validated by KeyFormatHelper."); - if (identifier.Parameters.HasValue) + if (identifier.HasParameters) { - AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); - identifier.Encode(writer); - throw Helpers.CreateAlgorithmUnknownException(writer); + throw Helpers.CreateAlgorithmUnknownException(in identifier); } return algorithm; diff --git a/src/libraries/Common/src/System/Security/Cryptography/X509Certificates/X509CertificateLoader.Pkcs12.cs b/src/libraries/Common/src/System/Security/Cryptography/X509Certificates/X509CertificateLoader.Pkcs12.cs index ebc771c69152ad..dc6c7dd045d1ea 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/X509Certificates/X509CertificateLoader.Pkcs12.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/X509Certificates/X509CertificateLoader.Pkcs12.cs @@ -577,15 +577,17 @@ static int GetRawKdfCount(in AlgorithmIdentifierAsn algorithmIdentifier) case Oids.Pkcs12PbeWithShaAnd2Key3Des: case Oids.Pkcs12PbeWithShaAnd128BitRC2: case Oids.Pkcs12PbeWithShaAnd40BitRC2: - PBEParameter pbeParameter = PBEParameter.Decode( - algorithmIdentifier.Parameters.Value, - AsnEncodingRules.BER); + ValuePBEParameter.Decode( + algorithmIdentifier.Parameters.Value.Span, + AsnEncodingRules.BER, + out ValuePBEParameter pbeParameter); return pbeParameter.IterationCount; case Oids.PasswordBasedEncryptionScheme2: - PBES2Params pbes2Params = PBES2Params.Decode( - algorithmIdentifier.Parameters.Value, - AsnEncodingRules.BER); + ValuePBES2Params.Decode( + algorithmIdentifier.Parameters.Value.Span, + AsnEncodingRules.BER, + out ValuePBES2Params pbes2Params); if (pbes2Params.KeyDerivationFunc.Algorithm != Oids.Pbkdf2) { @@ -595,14 +597,15 @@ static int GetRawKdfCount(in AlgorithmIdentifierAsn algorithmIdentifier) pbes2Params.EncryptionScheme.Algorithm)); } - if (!pbes2Params.KeyDerivationFunc.Parameters.HasValue) + if (!pbes2Params.KeyDerivationFunc.HasParameters) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - Pbkdf2Params pbkdf2Params = Pbkdf2Params.Decode( - pbes2Params.KeyDerivationFunc.Parameters.Value, - AsnEncodingRules.BER); + ValuePbkdf2Params.Decode( + pbes2Params.KeyDerivationFunc.Parameters, + AsnEncodingRules.BER, + out ValuePbkdf2Params pbkdf2Params); return pbkdf2Params.IterationCount; default: diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaImplementationTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaImplementationTests.cs index 996558d86fc0f0..425834743c014c 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaImplementationTests.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaImplementationTests.cs @@ -270,7 +270,7 @@ public static void ImportPkcs8PrivateKey_AlgorithmErrorsInAsn() // Create an invalid ML-DSA PKCS8 with parameters AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); - MLDsaPrivateKeyAsn seed = new MLDsaPrivateKeyAsn + ValueMLDsaPrivateKeyAsn seed = new ValueMLDsaPrivateKeyAsn { Seed = new byte[MLDsaAlgorithm.MLDsa44.PrivateSeedSizeInBytes], }; @@ -302,56 +302,56 @@ public static void ImportPkcs8PrivateKey_AlgorithmErrorsInAsn() [Fact] public static void ImportPkcs8PrivateKey_KeyErrorsInAsn() { - AssertInvalidAsn(new MLDsaPrivateKeyAsn + AssertInvalidAsn(new ValueMLDsaPrivateKeyAsn { - Both = new MLDsaPrivateKeyBothAsn() + Both = new ValueMLDsaPrivateKeyBothAsn(), }); - AssertInvalidAsn(new MLDsaPrivateKeyAsn + AssertInvalidAsn(new ValueMLDsaPrivateKeyAsn { - Both = new MLDsaPrivateKeyBothAsn + Both = new ValueMLDsaPrivateKeyBothAsn { Seed = new byte[MLDsaAlgorithm.MLDsa44.PrivateSeedSizeInBytes], - } + }, }); - AssertInvalidAsn(new MLDsaPrivateKeyAsn + AssertInvalidAsn(new ValueMLDsaPrivateKeyAsn { - Both = new MLDsaPrivateKeyBothAsn + Both = new ValueMLDsaPrivateKeyBothAsn { ExpandedKey = new byte[MLDsaAlgorithm.MLDsa44.PrivateKeySizeInBytes], - } + }, }); - AssertInvalidAsn(new MLDsaPrivateKeyAsn + AssertInvalidAsn(new ValueMLDsaPrivateKeyAsn { - Both = new MLDsaPrivateKeyBothAsn + Both = new ValueMLDsaPrivateKeyBothAsn { Seed = new byte[MLDsaAlgorithm.MLDsa44.PrivateSeedSizeInBytes - 1], ExpandedKey = new byte[MLDsaAlgorithm.MLDsa44.PrivateKeySizeInBytes], - } + }, }); - AssertInvalidAsn(new MLDsaPrivateKeyAsn + AssertInvalidAsn(new ValueMLDsaPrivateKeyAsn { - Both = new MLDsaPrivateKeyBothAsn + Both = new ValueMLDsaPrivateKeyBothAsn { Seed = new byte[MLDsaAlgorithm.MLDsa44.PrivateSeedSizeInBytes], ExpandedKey = new byte[MLDsaAlgorithm.MLDsa44.PrivateKeySizeInBytes - 1], - } + }, }); - AssertInvalidAsn(new MLDsaPrivateKeyAsn + AssertInvalidAsn(new ValueMLDsaPrivateKeyAsn { - Both = new MLDsaPrivateKeyBothAsn + Both = new ValueMLDsaPrivateKeyBothAsn { // This will also fail because the seed and expanded key mismatch Seed = new byte[MLDsaAlgorithm.MLDsa44.PrivateSeedSizeInBytes], ExpandedKey = new byte[MLDsaAlgorithm.MLDsa44.PrivateKeySizeInBytes], - } + }, }); - static void AssertInvalidAsn(MLDsaPrivateKeyAsn privateKeyAsn) + static void AssertInvalidAsn(ValueMLDsaPrivateKeyAsn privateKeyAsn) { PrivateKeyInfoAsn pkcs8 = new PrivateKeyInfoAsn { @@ -433,12 +433,12 @@ public static void AlgorithmMatches_GenerateKey(MLDsaAlgorithm algorithm) MLDsaTestHelpers.AssertImportPublicKey(import => AssertThrowIfNotSupported(() => - WithDispose(import(), mldsa => + WithDispose(import(), mldsa => Assert.Equal(algorithm, mldsa.Algorithm))), algorithm, publicKey); MLDsaTestHelpers.AssertImportPrivateKey(import => AssertThrowIfNotSupported(() => - WithDispose(import(), mldsa => + WithDispose(import(), mldsa => Assert.Equal(algorithm, mldsa.Algorithm))), algorithm, privateKey); MLDsaTestHelpers.AssertImportPrivateSeed(import => diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaTestHelpers.cs b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaTestHelpers.cs index 581e7ae8140660..07e274abc4e00e 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaTestHelpers.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AlgorithmImplementations/MLDsa/MLDsaTestHelpers.cs @@ -138,9 +138,9 @@ internal static void AssertImportPrivateKey(Action> testDirectCall, } AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); - MLDsaPrivateKeyAsn privateKeyAsn = new MLDsaPrivateKeyAsn + ValueMLDsaPrivateKeyAsn privateKeyAsn = new ValueMLDsaPrivateKeyAsn { - ExpandedKey = privateKey + ExpandedKey = privateKey, }; privateKeyAsn.Encode(writer); @@ -178,7 +178,7 @@ internal static void AssertImportPrivateSeed(Action> testDirectCall, } AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); - MLDsaPrivateKeyAsn privateKey = new MLDsaPrivateKeyAsn + ValueMLDsaPrivateKeyAsn privateKey = new ValueMLDsaPrivateKeyAsn { Seed = privateSeed, }; @@ -301,10 +301,29 @@ internal static void AssertExportMLDsaPrivateKey(Action> dir }); AssertExportPkcs8PrivateKey(exportPkcs8 => + { indirectCallback(mldsa => - MLDsaPrivateKeyAsn.Decode( - PrivateKeyInfoAsn.Decode( - exportPkcs8(mldsa), AsnEncodingRules.DER).PrivateKey, AsnEncodingRules.DER).ExpandedKey?.ToArray())); + { + ValuePrivateKeyInfoAsn.Decode( + exportPkcs8(mldsa), + AsnEncodingRules.DER, + out ValuePrivateKeyInfoAsn privateKeyInfo); + + ValueMLDsaPrivateKeyAsn.Decode( + privateKeyInfo.PrivateKey, + AsnEncodingRules.DER, + out ValueMLDsaPrivateKeyAsn mldsaPrivateKeyInfo); + + if (mldsaPrivateKeyInfo.HasExpandedKey) + { + return mldsaPrivateKeyInfo.ExpandedKey.ToArray(); + } + else + { + return null; + } + }); + }); } internal static void AssertExportMLDsaPrivateSeed(Action> callback) => @@ -320,10 +339,29 @@ internal static void AssertExportMLDsaPrivateSeed(Action> di }); AssertExportPkcs8PrivateKey(exportPkcs8 => + { indirectCallback(mldsa => - MLDsaPrivateKeyAsn.Decode( - PrivateKeyInfoAsn.Decode( - exportPkcs8(mldsa), AsnEncodingRules.DER).PrivateKey, AsnEncodingRules.DER).Seed?.ToArray())); + { + ValuePrivateKeyInfoAsn.Decode( + exportPkcs8(mldsa), + AsnEncodingRules.DER, + out ValuePrivateKeyInfoAsn privateKeyInfo); + + ValueMLDsaPrivateKeyAsn.Decode( + privateKeyInfo.PrivateKey, + AsnEncodingRules.DER, + out ValueMLDsaPrivateKeyAsn mldsaPrivateKeyInfo); + + if (mldsaPrivateKeyInfo.HasSeed) + { + return mldsaPrivateKeyInfo.Seed.ToArray(); + } + else + { + return null; + } + }); + }); } internal static void AssertExportPkcs8PrivateKey(MLDsa mldsa, Action callback) => diff --git a/src/libraries/Common/tests/System/Security/Cryptography/AsnUtils.cs b/src/libraries/Common/tests/System/Security/Cryptography/AsnUtils.cs index 680d27d7782b87..84198a7b89bc68 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/AsnUtils.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/AsnUtils.cs @@ -37,18 +37,25 @@ internal static void AssertEncryptedPkcs8PrivateKeyContents(EncryptedPrivateKeyI { // pbeWithSHA1And3-KeyTripleDES-CBC Assert.Equal("1.2.840.113549.1.12.1.3", algorithmIdentifier.Algorithm); - PBEParameter pbeParameterAsn = PBEParameter.Decode(algorithmIdentifier.Parameters.Value, AsnEncodingRules.BER); + ValuePBEParameter.Decode( + algorithmIdentifier.Parameters.Value.Span, + AsnEncodingRules.BER, + out ValuePBEParameter pbeParameterAsn); Assert.Equal(pbeParameters.IterationCount, pbeParameterAsn.IterationCount); } else { Assert.Equal("1.2.840.113549.1.5.13", algorithmIdentifier.Algorithm); // PBES2 - PBES2Params pbes2Params = PBES2Params.Decode(algorithmIdentifier.Parameters.Value, AsnEncodingRules.BER); + ValuePBES2Params.Decode( + algorithmIdentifier.Parameters.Value.Span, + AsnEncodingRules.BER, + out ValuePBES2Params pbes2Params); Assert.Equal("1.2.840.113549.1.5.12", pbes2Params.KeyDerivationFunc.Algorithm); // PBKDF2 - Pbkdf2Params pbkdf2Params = Pbkdf2Params.Decode( - pbes2Params.KeyDerivationFunc.Parameters.Value, - AsnEncodingRules.BER); + ValuePbkdf2Params.Decode( + pbes2Params.KeyDerivationFunc.Parameters, + AsnEncodingRules.BER, + out ValuePbkdf2Params pbkdf2Params); string expectedEncryptionOid = pbeParameters.EncryptionAlgorithm switch { PbeEncryptionAlgorithm.Aes128Cbc => "2.16.840.1.101.3.4.1.2", @@ -62,7 +69,7 @@ internal static void AssertEncryptedPkcs8PrivateKeyContents(EncryptedPrivateKeyI Assert.Equal(expectedEncryptionOid, pbes2Params.EncryptionScheme.Algorithm); } - static HashAlgorithmName GetHashAlgorithmFromPbkdf2Params(Pbkdf2Params pbkdf2Params) + static HashAlgorithmName GetHashAlgorithmFromPbkdf2Params(in ValuePbkdf2Params pbkdf2Params) { return pbkdf2Params.Prf.Algorithm switch { diff --git a/src/libraries/Common/tests/System/Security/Cryptography/MLKemBaseTests.cs b/src/libraries/Common/tests/System/Security/Cryptography/MLKemBaseTests.cs index 5f97ca8d3d576a..fbc4c3b87870d6 100644 --- a/src/libraries/Common/tests/System/Security/Cryptography/MLKemBaseTests.cs +++ b/src/libraries/Common/tests/System/Security/Cryptography/MLKemBaseTests.cs @@ -566,18 +566,25 @@ private static void AssertEncryptedPkcs8PrivateKeyContents(PbeParameters pbePara { // pbeWithSHA1And3-KeyTripleDES-CBC Assert.Equal("1.2.840.113549.1.12.1.3", algorithmIdentifier.Algorithm); - PBEParameter pbeParameterAsn = PBEParameter.Decode(algorithmIdentifier.Parameters.Value, AsnEncodingRules.BER); + ValuePBEParameter.Decode( + algorithmIdentifier.Parameters.Value.Span, + AsnEncodingRules.BER, + out ValuePBEParameter pbeParameterAsn); Assert.Equal(pbeParameters.IterationCount, pbeParameterAsn.IterationCount); } else { Assert.Equal("1.2.840.113549.1.5.13", algorithmIdentifier.Algorithm); // PBES2 - PBES2Params pbes2Params = PBES2Params.Decode(algorithmIdentifier.Parameters.Value, AsnEncodingRules.BER); + ValuePBES2Params.Decode( + algorithmIdentifier.Parameters.Value.Span, + AsnEncodingRules.BER, + out ValuePBES2Params pbes2Params); Assert.Equal("1.2.840.113549.1.5.12", pbes2Params.KeyDerivationFunc.Algorithm); // PBKDF2 - Pbkdf2Params pbkdf2Params = Pbkdf2Params.Decode( - pbes2Params.KeyDerivationFunc.Parameters.Value, - AsnEncodingRules.BER); + ValuePbkdf2Params.Decode( + pbes2Params.KeyDerivationFunc.Parameters, + AsnEncodingRules.BER, + out ValuePbkdf2Params pbkdf2Params); string expectedEncryptionOid = pbeParameters.EncryptionAlgorithm switch { PbeEncryptionAlgorithm.Aes128Cbc => "2.16.840.1.101.3.4.1.2", @@ -592,7 +599,7 @@ private static void AssertEncryptedPkcs8PrivateKeyContents(PbeParameters pbePara } } - private static HashAlgorithmName GetHashAlgorithmFromPbkdf2Params(Pbkdf2Params pbkdf2Params) + private static HashAlgorithmName GetHashAlgorithmFromPbkdf2Params(in ValuePbkdf2Params pbkdf2Params) { return pbkdf2Params.Prf.Algorithm switch { diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientIdentifierAsn.xml.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientIdentifierAsn.xml.cs index b29d1b966ad769..b6f5dff5dcb9c4 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientIdentifierAsn.xml.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/KeyAgreeRecipientIdentifierAsn.xml.cs @@ -8,14 +8,10 @@ namespace System.Security.Cryptography.Pkcs.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct KeyAgreeRecipientIdentifierAsn - { - internal System.Security.Cryptography.Asn1.Pkcs7.IssuerAndSerialNumberAsn? IssuerAndSerialNumber; - internal System.Security.Cryptography.Pkcs.Asn1.RecipientKeyIdentifier? RKeyId; - #if DEBUG - static KeyAgreeRecipientIdentifierAsn() + file static class ValidateKeyAgreeRecipientIdentifierAsn + { + static ValidateKeyAgreeRecipientIdentifierAsn() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -31,6 +27,25 @@ static KeyAgreeRecipientIdentifierAsn() ensureUniqueTag(Asn1Tag.Sequence, "IssuerAndSerialNumber"); ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "RKeyId"); } + + [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 KeyAgreeRecipientIdentifierAsn + { + internal System.Security.Cryptography.Asn1.Pkcs7.IssuerAndSerialNumberAsn? IssuerAndSerialNumber; + internal System.Security.Cryptography.Pkcs.Asn1.RecipientKeyIdentifier? RKeyId; + +#if DEBUG + static KeyAgreeRecipientIdentifierAsn() + { + ValidateKeyAgreeRecipientIdentifierAsn.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.xml.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.xml.cs index afa4625be943a9..3c0a07d01952f7 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.xml.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.xml.cs @@ -96,6 +96,28 @@ internal ref partial struct ValueMessageImprint internal ReadOnlySpan HashAlgorithm; internal ReadOnlySpan HashedMessage; + internal readonly void Encode(AsnWriter writer) + { + Encode(writer, Asn1Tag.Sequence); + } + + internal readonly void Encode(AsnWriter writer, Asn1Tag tag) + { + writer.PushSequence(tag); + + + try + { + writer.WriteEncodedValue(HashAlgorithm); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + writer.WriteOctetString(HashedMessage); + writer.PopSequence(tag); + } + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueMessageImprint decoded) { Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorIdentifierOrKeyAsn.xml.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorIdentifierOrKeyAsn.xml.cs index 6af892c37df1ae..40226a40064abd 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorIdentifierOrKeyAsn.xml.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/OriginatorIdentifierOrKeyAsn.xml.cs @@ -8,15 +8,10 @@ namespace System.Security.Cryptography.Pkcs.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct OriginatorIdentifierOrKeyAsn - { - internal System.Security.Cryptography.Asn1.Pkcs7.IssuerAndSerialNumberAsn? IssuerAndSerialNumber; - internal ReadOnlyMemory? SubjectKeyIdentifier; - internal System.Security.Cryptography.Pkcs.Asn1.OriginatorPublicKeyAsn? OriginatorKey; - #if DEBUG - static OriginatorIdentifierOrKeyAsn() + file static class ValidateOriginatorIdentifierOrKeyAsn + { + static ValidateOriginatorIdentifierOrKeyAsn() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -33,6 +28,26 @@ static OriginatorIdentifierOrKeyAsn() ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "SubjectKeyIdentifier"); ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 1), "OriginatorKey"); } + + [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 OriginatorIdentifierOrKeyAsn + { + internal System.Security.Cryptography.Asn1.Pkcs7.IssuerAndSerialNumberAsn? IssuerAndSerialNumber; + internal ReadOnlyMemory? SubjectKeyIdentifier; + internal System.Security.Cryptography.Pkcs.Asn1.OriginatorPublicKeyAsn? OriginatorKey; + +#if DEBUG + static OriginatorIdentifierOrKeyAsn() + { + ValidateOriginatorIdentifierOrKeyAsn.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientIdentifierAsn.xml.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientIdentifierAsn.xml.cs index 55dcec7e099199..3e5392d5879287 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientIdentifierAsn.xml.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientIdentifierAsn.xml.cs @@ -8,14 +8,10 @@ namespace System.Security.Cryptography.Pkcs.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct RecipientIdentifierAsn - { - internal System.Security.Cryptography.Asn1.Pkcs7.IssuerAndSerialNumberAsn? IssuerAndSerialNumber; - internal ReadOnlyMemory? SubjectKeyIdentifier; - #if DEBUG - static RecipientIdentifierAsn() + file static class ValidateRecipientIdentifierAsn + { + static ValidateRecipientIdentifierAsn() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -31,6 +27,25 @@ static RecipientIdentifierAsn() ensureUniqueTag(Asn1Tag.Sequence, "IssuerAndSerialNumber"); ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "SubjectKeyIdentifier"); } + + [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 RecipientIdentifierAsn + { + internal System.Security.Cryptography.Asn1.Pkcs7.IssuerAndSerialNumberAsn? IssuerAndSerialNumber; + internal ReadOnlyMemory? SubjectKeyIdentifier; + +#if DEBUG + static RecipientIdentifierAsn() + { + ValidateRecipientIdentifierAsn.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientInfoAsn.xml.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientInfoAsn.xml.cs index 4cfc6308e71f1d..61d978cc1186ed 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientInfoAsn.xml.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/RecipientInfoAsn.xml.cs @@ -8,14 +8,10 @@ namespace System.Security.Cryptography.Pkcs.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct RecipientInfoAsn - { - internal System.Security.Cryptography.Pkcs.Asn1.KeyTransRecipientInfoAsn? Ktri; - internal System.Security.Cryptography.Pkcs.Asn1.KeyAgreeRecipientInfoAsn? Kari; - #if DEBUG - static RecipientInfoAsn() + file static class ValidateRecipientInfoAsn + { + static ValidateRecipientInfoAsn() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -31,6 +27,25 @@ static RecipientInfoAsn() ensureUniqueTag(Asn1Tag.Sequence, "Ktri"); ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 1), "Kari"); } + + [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 RecipientInfoAsn + { + internal System.Security.Cryptography.Pkcs.Asn1.KeyTransRecipientInfoAsn? Ktri; + internal System.Security.Cryptography.Pkcs.Asn1.KeyAgreeRecipientInfoAsn? Kari; + +#if DEBUG + static RecipientInfoAsn() + { + ValidateRecipientInfoAsn.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.xml.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.xml.cs index 1a71b5f83937ff..b8479444370505 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.xml.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/Rfc3161TstInfo.xml.cs @@ -244,12 +244,121 @@ internal ref partial struct ValueRfc3161TstInfo internal DateTimeOffset GenTime; internal System.Security.Cryptography.Pkcs.Asn1.Rfc3161Accuracy? Accuracy; internal bool Ordering; - internal ReadOnlySpan Nonce; - internal bool HasNonce; - internal ReadOnlySpan Tsa; - internal bool HasTsa; - internal ReadOnlySpan Extensions; - internal bool HasExtensions; + + internal ReadOnlySpan Nonce + { + get; + set + { + HasNonce = true; + field = value; + } + } + + internal bool HasNonce { get; private set; } + + internal ReadOnlySpan Tsa + { + get; + set + { + HasTsa = true; + field = value; + } + } + + internal bool HasTsa { get; private set; } + + internal ReadOnlySpan Extensions + { + get; + set + { + HasExtensions = true; + field = value; + } + } + + internal bool HasExtensions { get; private set; } + + internal readonly void Encode(AsnWriter writer) + { + Encode(writer, Asn1Tag.Sequence); + } + + internal readonly void Encode(AsnWriter writer, Asn1Tag tag) + { + writer.PushSequence(tag); + + writer.WriteInteger(Version); + try + { + writer.WriteObjectIdentifier(Policy); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + MessageImprint.Encode(writer); + writer.WriteInteger(SerialNumber); + writer.WriteGeneralizedTime(GenTime, false); + + if (Accuracy.HasValue) + { + Accuracy.Value.Encode(writer); + } + + + // DEFAULT value handler for Ordering. + { + const int AsnBoolDerEncodeSize = 3; + AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER, initialCapacity: AsnBoolDerEncodeSize); + tmp.WriteBoolean(Ordering); + + if (!tmp.EncodedValueEquals(SharedRfc3161TstInfo.DefaultOrdering)) + { + tmp.CopyTo(writer); + } + } + + + if (HasNonce) + { + writer.WriteInteger(Nonce); + } + + + if (HasTsa) + { + writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); + + try + { + writer.WriteEncodedValue(Tsa); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + writer.PopSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); + } + + + if (HasExtensions) + { + + try + { + writer.WriteEncodedValue(Extensions); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + } + + writer.PopSequence(tag); + } internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueRfc3161TstInfo decoded) { diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SignedAttributesSet.xml.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SignedAttributesSet.xml.cs index 98979aaf1abc5a..225c073f1b8b39 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SignedAttributesSet.xml.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/SignedAttributesSet.xml.cs @@ -9,13 +9,10 @@ namespace System.Security.Cryptography.Pkcs { - [StructLayout(LayoutKind.Sequential)] - internal partial struct SignedAttributesSet - { - internal System.Security.Cryptography.Asn1.AttributeAsn[]? SignedAttributes; - #if DEBUG - static SignedAttributesSet() + file static class ValidateSignedAttributesSet + { + static ValidateSignedAttributesSet() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -30,6 +27,24 @@ static SignedAttributesSet() ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "SignedAttributes"); } + + [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 SignedAttributesSet + { + internal System.Security.Cryptography.Asn1.AttributeAsn[]? SignedAttributes; + +#if DEBUG + static SignedAttributesSet() + { + ValidateSignedAttributesSet.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.RSA.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.RSA.cs index 557f7c94e4e4f8..e6788d5e22cd5c 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.RSA.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/CmsSignature.RSA.cs @@ -311,7 +311,10 @@ protected override RSASignaturePadding GetSignaturePadding( throw new CryptographicException(SR.Cryptography_Pkcs_PssParametersMissing); } - PssParamsAsn pssParams = PssParamsAsn.Decode(signatureParameters.Value, AsnEncodingRules.DER); + ValuePssParamsAsn.Decode( + signatureParameters.Value.Span, + AsnEncodingRules.DER, + out ValuePssParamsAsn pssParams); if (pssParams.HashAlgorithm.Algorithm != digestAlgorithmOid) { diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/EccKeyFormatHelper.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/EccKeyFormatHelper.cs index 25826217d325c2..f603bf17a182b4 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/EccKeyFormatHelper.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/EccKeyFormatHelper.cs @@ -35,16 +35,6 @@ internal static void ReadSubjectPublicKeyInfo( out key); } - internal static ReadOnlyMemory ReadSubjectPublicKeyInfo( - ReadOnlyMemory source, - out int bytesRead) - { - return KeyFormatHelper.ReadSubjectPublicKeyInfo( - s_validOids, - source, - out bytesRead); - } - internal static void ReadEncryptedPkcs8( ReadOnlySpan source, ReadOnlySpan password, @@ -75,7 +65,7 @@ internal static void ReadEncryptedPkcs8( out key); } - internal static unsafe ECParameters FromECPrivateKey(ReadOnlySpan key, out int bytesRead) + internal static ECParameters FromECPrivateKey(ReadOnlySpan key, out int bytesRead) { try { @@ -86,16 +76,10 @@ internal static unsafe ECParameters FromECPrivateKey(ReadOnlySpan key, out out _, out int firstValueLength); - fixed (byte* ptr = &MemoryMarshal.GetReference(key)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, firstValueLength)) - { - AlgorithmIdentifierAsn algId = default; - FromECPrivateKey(manager.Memory, algId, out ECParameters ret); - bytesRead = firstValueLength; - return ret; - } - } + ValueAlgorithmIdentifierAsn algId = default; + FromECPrivateKey(key.Slice(0, firstValueLength), algId, out ECParameters ret); + bytesRead = firstValueLength; + return ret; } catch (AsnContentException e) { @@ -104,20 +88,20 @@ internal static unsafe ECParameters FromECPrivateKey(ReadOnlySpan key, out } internal static void FromECPrivateKey( - ReadOnlyMemory keyData, - in AlgorithmIdentifierAsn algId, + ReadOnlySpan keyData, + in ValueAlgorithmIdentifierAsn algId, out ECParameters ret) { - ECPrivateKey key = ECPrivateKey.Decode(keyData, AsnEncodingRules.BER); + ValueECPrivateKey.Decode(keyData, AsnEncodingRules.BER, out ValueECPrivateKey key); FromECPrivateKey(key, algId, out ret); } internal static void FromECPrivateKey( - ECPrivateKey key, - in AlgorithmIdentifierAsn algId, + ValueECPrivateKey key, + in ValueAlgorithmIdentifierAsn algId, out ECParameters ret) { - ValidateParameters(key.Parameters, algId); + ValidateParameters(key, algId); if (key.Version != 1) { @@ -127,9 +111,9 @@ internal static void FromECPrivateKey( byte[]? x = null; byte[]? y = null; - if (key.PublicKey is not null) + if (key.HasPublicKey) { - ReadOnlySpan publicKeyBytes = key.PublicKey.Value.Span; + ReadOnlySpan publicKeyBytes = key.PublicKey; if (publicKeyBytes.Length == 0) { @@ -153,15 +137,16 @@ internal static void FromECPrivateKey( y = publicKeyBytes.Slice(1 + key.PrivateKey.Length).ToArray(); } - ECDomainParameters domainParameters; + ValueECDomainParameters domainParameters; - if (key.Parameters != null) + if (key.HasParameters) { - domainParameters = key.Parameters.Value; + domainParameters = key.Parameters; } else { - domainParameters = ECDomainParameters.Decode(algId.Parameters!.Value, AsnEncodingRules.DER); + Debug.Assert(algId.HasParameters); + ValueECDomainParameters.Decode(algId.Parameters, AsnEncodingRules.DER, out domainParameters); } Debug.Assert((x == null) == (y == null)); @@ -181,16 +166,16 @@ internal static void FromECPrivateKey( } internal static void FromECPublicKey( - ReadOnlyMemory key, - in AlgorithmIdentifierAsn algId, + ReadOnlySpan key, + in ValueAlgorithmIdentifierAsn algId, out ECParameters ret) { - if (algId.Parameters == null) + if (!algId.HasParameters) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - ReadOnlySpan publicKeyBytes = key.Span; + ReadOnlySpan publicKeyBytes = key; if (publicKeyBytes.Length == 0) { @@ -212,9 +197,10 @@ internal static void FromECPublicKey( int fieldWidth = publicKeyBytes.Length / 2; - ECDomainParameters domainParameters = ECDomainParameters.Decode( - algId.Parameters.Value, - AsnEncodingRules.DER); + ValueECDomainParameters.Decode( + algId.Parameters, + AsnEncodingRules.DER, + out ValueECDomainParameters domainParameters); ret = new ECParameters { @@ -229,24 +215,24 @@ internal static void FromECPublicKey( ret.Validate(); } - private static void ValidateParameters(ECDomainParameters? keyParameters, in AlgorithmIdentifierAsn algId) + private static void ValidateParameters(in ValueECPrivateKey ecPrivateKey, in ValueAlgorithmIdentifierAsn algId) { // At least one is required - if (keyParameters == null && algId.Parameters == null) + if (!ecPrivateKey.HasParameters && !algId.HasParameters) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } // If they are both specified they must match. - if (keyParameters != null && algId.Parameters != null) + if (ecPrivateKey.HasParameters && algId.HasParameters) { - ReadOnlySpan algIdParameters = algId.Parameters.Value.Span; + ReadOnlySpan algIdParameters = algId.Parameters; // X.509 SubjectPublicKeyInfo specifies DER encoding. // RFC 5915 specifies DER encoding for EC Private Keys. // So we can compare as DER. AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); - keyParameters.Value.Encode(writer); + ecPrivateKey.Parameters.Encode(writer); if (!writer.EncodedValueEquals(algIdParameters)) { @@ -255,14 +241,14 @@ private static void ValidateParameters(ECDomainParameters? keyParameters, in Alg } } - private static ECCurve GetCurve(ECDomainParameters domainParameters) + private static ECCurve GetCurve(in ValueECDomainParameters domainParameters) { - if (domainParameters.Specified.HasValue) + if (domainParameters.HasSpecified) { - return GetSpecifiedECCurve(domainParameters.Specified.Value); + return GetSpecifiedECCurve(domainParameters.Specified); } - if (domainParameters.Named == null) + if (domainParameters.Named is null) { throw new CryptographicException(SR.Cryptography_ECC_NamedCurvesOnly); } @@ -277,7 +263,7 @@ private static ECCurve GetCurve(ECDomainParameters domainParameters) return ECCurve.CreateFromOid(curveOid); } - private static ECCurve GetSpecifiedECCurve(SpecifiedECDomain specifiedParameters) + private static ECCurve GetSpecifiedECCurve(in ValueSpecifiedECDomain specifiedParameters) { try { @@ -289,7 +275,7 @@ private static ECCurve GetSpecifiedECCurve(SpecifiedECDomain specifiedParameters } } - private static ECCurve GetSpecifiedECCurveCore(SpecifiedECDomain specifiedParameters) + private static ECCurve GetSpecifiedECCurveCore(in ValueSpecifiedECDomain specifiedParameters) { // sec1-v2 C.3: // @@ -301,7 +287,7 @@ private static ECCurve GetSpecifiedECCurveCore(SpecifiedECDomain specifiedParame throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } - if (specifiedParameters.Version > 1 && !specifiedParameters.Curve.Seed.HasValue) + if (specifiedParameters.Version > 1 && !specifiedParameters.Curve.HasSeed) { throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } @@ -313,7 +299,7 @@ private static ECCurve GetSpecifiedECCurveCore(SpecifiedECDomain specifiedParame { case Oids.EcPrimeField: prime = true; - ValueAsnReader primeReader = new(specifiedParameters.FieldID.Parameters.Span, AsnEncodingRules.BER); + ValueAsnReader primeReader = new(specifiedParameters.FieldID.Parameters, AsnEncodingRules.BER); ReadOnlySpan primeValue = primeReader.ReadIntegerBytes(); primeReader.ThrowIfNotEmpty(); @@ -331,7 +317,7 @@ private static ECCurve GetSpecifiedECCurveCore(SpecifiedECDomain specifiedParame break; case Oids.EcChar2Field: prime = false; - ValueAsnReader char2Reader = new(specifiedParameters.FieldID.Parameters.Span, AsnEncodingRules.BER); + ValueAsnReader char2Reader = new(specifiedParameters.FieldID.Parameters, AsnEncodingRules.BER); ValueAsnReader innerReader = char2Reader.ReadSequence(); char2Reader.ThrowIfNotEmpty(); @@ -432,7 +418,7 @@ private static ECCurve GetSpecifiedECCurveCore(SpecifiedECDomain specifiedParame curve.B = specifiedParameters.Curve.B.ToUnsignedIntegerBytes(primeOrPoly.Length); curve.Order = specifiedParameters.Order.ToUnsignedIntegerBytes(primeOrPoly.Length); - ReadOnlySpan baseSpan = specifiedParameters.Base.Span; + ReadOnlySpan baseSpan = specifiedParameters.Base; // We only understand the uncompressed point encoding, but that's almost always what's used. if (baseSpan[0] != 0x04 || baseSpan.Length != 2 * primeOrPoly.Length + 1) @@ -443,9 +429,9 @@ private static ECCurve GetSpecifiedECCurveCore(SpecifiedECDomain specifiedParame curve.G.X = baseSpan.Slice(1, primeOrPoly.Length).ToArray(); curve.G.Y = baseSpan.Slice(1 + primeOrPoly.Length).ToArray(); - if (specifiedParameters.Cofactor.HasValue) + if (specifiedParameters.HasCofactor) { - curve.Cofactor = specifiedParameters.Cofactor.Value.ToUnsignedIntegerBytes(); + curve.Cofactor = specifiedParameters.Cofactor.ToUnsignedIntegerBytes(); } return curve; @@ -490,7 +476,9 @@ private static void WriteAlgorithmIdentifier(in ECParameters ecParameters, AsnWr writer.PopSequence(); } - internal static AsnWriter WritePkcs8PrivateKey(ECParameters ecParameters, AttributeAsn[]? attributes = null) + internal static AsnWriter WritePkcs8PrivateKey( + ECParameters ecParameters, + ReadOnlySpan encodedAttributes = default) { ecParameters.Validate(); @@ -502,27 +490,18 @@ internal static AsnWriter WritePkcs8PrivateKey(ECParameters ecParameters, Attrib // Don't need the domain parameters because they're contained in the algId. AsnWriter ecPrivateKey = WriteEcPrivateKey(ecParameters, includeDomainParameters: false); AsnWriter algorithmIdentifier = WriteAlgorithmIdentifier(ecParameters); - AsnWriter? attributeWriter = WritePrivateKeyInfoAttributes(attributes); + AsnWriter? attributeWriter = WritePrivateKeyInfoAttributes(encodedAttributes); return KeyFormatHelper.WritePkcs8(algorithmIdentifier, ecPrivateKey, attributeWriter); } - [return: NotNullIfNotNull(nameof(attributes))] - private static AsnWriter? WritePrivateKeyInfoAttributes(AttributeAsn[]? attributes) + private static AsnWriter? WritePrivateKeyInfoAttributes(ReadOnlySpan encodedAttributes) { - if (attributes == null) + if (encodedAttributes.IsEmpty) return null; AsnWriter writer = new AsnWriter(AsnEncodingRules.DER); - Asn1Tag tag = new Asn1Tag(TagClass.ContextSpecific, 0); - writer.PushSetOf(tag); - - for (int i = 0; i < attributes.Length; i++) - { - attributes[i].Encode(writer); - } - - writer.PopSetOf(tag); + writer.WriteEncodedValueForCrypto(encodedAttributes); return writer; } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/KeyBlobHelpers.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/KeyBlobHelpers.cs index 22c10081c26107..6ef5402eac4ecd 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/KeyBlobHelpers.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/KeyBlobHelpers.cs @@ -9,14 +9,17 @@ internal static partial class KeyBlobHelpers { internal static byte[] ToUnsignedIntegerBytes(this ReadOnlyMemory memory, int length) { - if (memory.Length == length) + return ToUnsignedIntegerBytes(memory.Span, length); + } + + internal static byte[] ToUnsignedIntegerBytes(this ReadOnlySpan span, int length) + { + if (span.Length == length) { - return memory.ToArray(); + return span.ToArray(); } - ReadOnlySpan span = memory.Span; - - if (memory.Length == length + 1) + if (span.Length == length + 1) { if (span[0] == 0) { diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSA.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSA.cs index e9454c4f76a7f6..36723978608a75 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSA.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/RSA.cs @@ -874,21 +874,15 @@ private unsafe AsnWriter WritePkcs1PrivateKey() public override unsafe void ImportSubjectPublicKeyInfo(ReadOnlySpan source, out int bytesRead) { - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - ReadOnlyMemory pkcs1 = RSAKeyFormatHelper.ReadSubjectPublicKeyInfo( - manager.Memory, - out int localRead); + ReadOnlySpan pkcs1 = RSAKeyFormatHelper.ReadSubjectPublicKeyInfo( + source, + out int localRead); - ImportRSAPublicKey(pkcs1.Span, out _); - bytesRead = localRead; - } - } + ImportRSAPublicKey(pkcs1, out _); + bytesRead = localRead; } - public virtual unsafe void ImportRSAPublicKey(ReadOnlySpan source, out int bytesRead) + public virtual void ImportRSAPublicKey(ReadOnlySpan source, out int bytesRead) { try { @@ -899,18 +893,12 @@ public virtual unsafe void ImportRSAPublicKey(ReadOnlySpan source, out int out _, out int localRead); - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, localRead)) - { - AlgorithmIdentifierAsn ignored = default; - RSAKeyFormatHelper.ReadRsaPublicKey(manager.Memory, ignored, out RSAParameters rsaParameters); + ValueAlgorithmIdentifierAsn ignored = default; + RSAKeyFormatHelper.ReadRsaPublicKey(source.Slice(0, localRead), ignored, out RSAParameters rsaParameters); - ImportParameters(rsaParameters); + ImportParameters(rsaParameters); - bytesRead = localRead; - } - } + bytesRead = localRead; } catch (AsnContentException e) { @@ -947,18 +935,10 @@ public virtual unsafe void ImportRSAPrivateKey(ReadOnlySpan source, out in public override unsafe void ImportPkcs8PrivateKey(ReadOnlySpan source, out int bytesRead) { - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - { - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - ReadOnlyMemory pkcs1 = RSAKeyFormatHelper.ReadPkcs8( - manager.Memory, - out int localRead); + ReadOnlySpan pkcs1 = RSAKeyFormatHelper.ReadPkcs8(source, out int localRead); - ImportRSAPrivateKey(pkcs1.Span, out _); - bytesRead = localRead; - } - } + ImportRSAPrivateKey(pkcs1, out _); + bytesRead = localRead; } public override unsafe void ImportEncryptedPkcs8PrivateKey( diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/CertificationRequestInfoAsn.xml.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/CertificationRequestInfoAsn.xml.cs index 12ac6712256a99..039aa29f2316e0 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/CertificationRequestInfoAsn.xml.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/CertificationRequestInfoAsn.xml.cs @@ -141,6 +141,48 @@ internal ref partial struct ValueCertificationRequestInfoAsn internal System.Security.Cryptography.Asn1.ValueSubjectPublicKeyInfoAsn SubjectPublicKeyInfo; internal ReadOnlySpan Attributes; + internal readonly void Encode(AsnWriter writer) + { + Encode(writer, Asn1Tag.Sequence); + } + + internal readonly void Encode(AsnWriter writer, Asn1Tag tag) + { + writer.PushSequence(tag); + + writer.WriteInteger(Version); + + // Validator for tag constraint for Subject + { + if (!Asn1Tag.TryDecode(Subject, out Asn1Tag validateTag, out _) || + !validateTag.HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16))) + { + throw new CryptographicException(); + } + } + + + try + { + writer.WriteEncodedValue(Subject); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + SubjectPublicKeyInfo.Encode(writer); + + try + { + writer.WriteEncodedValue(Attributes); + } + catch (ArgumentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); + } + writer.PopSequence(tag); + } + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueCertificationRequestInfoAsn decoded) { Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointNameAsn.xml.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointNameAsn.xml.cs index 4bfd5b430468ce..c7446dce138cf7 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointNameAsn.xml.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/DistributionPointNameAsn.xml.cs @@ -9,14 +9,10 @@ namespace System.Security.Cryptography.X509Certificates.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct DistributionPointNameAsn - { - internal System.Security.Cryptography.Asn1.GeneralNameAsn[]? FullName; - internal ReadOnlyMemory? NameRelativeToCRLIssuer; - #if DEBUG - static DistributionPointNameAsn() + file static class ValidateDistributionPointNameAsn + { + static ValidateDistributionPointNameAsn() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -32,6 +28,25 @@ static DistributionPointNameAsn() ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 0), "FullName"); ensureUniqueTag(new Asn1Tag(TagClass.ContextSpecific, 1), "NameRelativeToCRLIssuer"); } + + [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 DistributionPointNameAsn + { + internal System.Security.Cryptography.Asn1.GeneralNameAsn[]? FullName; + internal ReadOnlyMemory? NameRelativeToCRLIssuer; + +#if DEBUG + static DistributionPointNameAsn() + { + ValidateDistributionPointNameAsn.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/TimeAsn.xml.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/TimeAsn.xml.cs index d2bf4635bb0347..1c303d6bb661b3 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/TimeAsn.xml.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/TimeAsn.xml.cs @@ -8,14 +8,10 @@ namespace System.Security.Cryptography.X509Certificates.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct TimeAsn - { - internal DateTimeOffset? UtcTime; - internal DateTimeOffset? GeneralTime; - #if DEBUG - static TimeAsn() + file static class ValidateTimeAsn + { + static ValidateTimeAsn() { var usedTags = new System.Collections.Generic.Dictionary(); Action ensureUniqueTag = (tag, fieldName) => @@ -31,6 +27,25 @@ static TimeAsn() ensureUniqueTag(Asn1Tag.UtcTime, "UtcTime"); ensureUniqueTag(Asn1Tag.GeneralizedTime, "GeneralTime"); } + + [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 TimeAsn + { + internal DateTimeOffset? UtcTime; + internal DateTimeOffset? GeneralTime; + +#if DEBUG + static TimeAsn() + { + ValidateTimeAsn.Validate(); + } #endif internal readonly void Encode(AsnWriter writer) diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs index c1daad2b756e25..d34d4d248915e1 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/RSAPssX509SignatureGenerator.cs @@ -70,10 +70,10 @@ public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlg // * don't allow custom trailer // we don't have to worry about any of the DEFAULTs. (specify, specify, specify, omit). - PssParamsAsn parameters = new PssParamsAsn + ValuePssParamsAsn parameters = new ValuePssParamsAsn { - HashAlgorithm = new AlgorithmIdentifierAsn { Algorithm = digestOid }, - MaskGenAlgorithm = new AlgorithmIdentifierAsn { Algorithm = Oids.Mgf1 }, + HashAlgorithm = new ValueAlgorithmIdentifierAsn { Algorithm = digestOid }, + MaskGenAlgorithm = new ValueAlgorithmIdentifierAsn { Algorithm = Oids.Mgf1 }, SaltLength = cbSalt, TrailerField = 1, }; @@ -90,7 +90,7 @@ public override byte[] GetSignatureAlgorithmIdentifier(HashAlgorithmName hashAlg parameters.Encode(writer); - AlgorithmIdentifierAsn identifier = new AlgorithmIdentifierAsn + ValueAlgorithmIdentifierAsn identifier = new ValueAlgorithmIdentifierAsn { Algorithm = Oids.RsaPss, Parameters = writer.Encode(), diff --git a/src/libraries/System.Security.Cryptography/tests/X509Certificates/ExportTests.cs b/src/libraries/System.Security.Cryptography/tests/X509Certificates/ExportTests.cs index 7f13477421e654..649ab7697747d7 100644 --- a/src/libraries/System.Security.Cryptography/tests/X509Certificates/ExportTests.cs +++ b/src/libraries/System.Security.Cryptography/tests/X509Certificates/ExportTests.cs @@ -1001,18 +1001,25 @@ void AssertEncryptionAlgorithm(AlgorithmIdentifierAsn algorithmIdentifier) { // pbeWithSHA1And3-KeyTripleDES-CBC Assert.Equal("1.2.840.113549.1.12.1.3", algorithmIdentifier.Algorithm); - PBEParameter pbeParameter = PBEParameter.Decode(algorithmIdentifier.Parameters.Value, AsnEncodingRules.BER); + ValuePBEParameter.Decode( + algorithmIdentifier.Parameters.Value.Span, + AsnEncodingRules.BER, + out ValuePBEParameter pbeParameter); Assert.Equal(expectedIterations, pbeParameter.IterationCount); } else { Assert.Equal("1.2.840.113549.1.5.13", algorithmIdentifier.Algorithm); // PBES2 - PBES2Params pbes2Params = PBES2Params.Decode(algorithmIdentifier.Parameters.Value, AsnEncodingRules.BER); + ValuePBES2Params.Decode( + algorithmIdentifier.Parameters.Value.Span, + AsnEncodingRules.BER, + out ValuePBES2Params pbes2Params); Assert.Equal("1.2.840.113549.1.5.12", pbes2Params.KeyDerivationFunc.Algorithm); // PBKDF2 - Pbkdf2Params pbkdf2Params = Pbkdf2Params.Decode( - pbes2Params.KeyDerivationFunc.Parameters.Value, - AsnEncodingRules.BER); + ValuePbkdf2Params.Decode( + pbes2Params.KeyDerivationFunc.Parameters, + AsnEncodingRules.BER, + out ValuePbkdf2Params pbkdf2Params); string expectedEncryptionOid = expectedEncryptionAlgorithm switch { PbeEncryptionAlgorithm.Aes128Cbc => "2.16.840.1.101.3.4.1.2", @@ -1028,7 +1035,7 @@ void AssertEncryptionAlgorithm(AlgorithmIdentifierAsn algorithmIdentifier) } } - private static HashAlgorithmName GetHashAlgorithmFromPbkdf2Params(Pbkdf2Params pbkdf2Params) + private static HashAlgorithmName GetHashAlgorithmFromPbkdf2Params(in ValuePbkdf2Params pbkdf2Params) { return pbkdf2Params.Prf.Algorithm switch {