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 058093035af1ec..b8a5da88b67b47 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 @@ -59,4 +59,59 @@ internal static bool RepresentsNull(ReadOnlyMemory? parameters) return span[1] == 0; } } + + internal ref partial struct ValueAlgorithmIdentifierAsn + { + internal static ReadOnlySpan ExplicitDerNull => [0x05, 0x00]; + + internal bool Equals(ref readonly ValueAlgorithmIdentifierAsn other) + { + if (Algorithm != other.Algorithm) + { + return false; + } + + bool isNull = RepresentsNull(ref this); + bool isOtherNull = RepresentsNull(in other); + + if (isNull != isOtherNull) + { + return false; + } + + if (isNull) + { + return true; + } + + return Parameters.SequenceEqual(other.Parameters); + } + + internal readonly bool HasNullEquivalentParameters() + { + return RepresentsNull(in this); + } + + internal static bool RepresentsNull(ref readonly ValueAlgorithmIdentifierAsn algorithm) + { + if (!algorithm.HasParameters) + { + return true; + } + + ReadOnlySpan span = algorithm.Parameters; + + if (span.Length != 2) + { + return false; + } + + if (span[0] != 0x05) + { + return false; + } + + return span[1] == 0; + } + } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml index 980d0f2d6fb0e2..29cfb3d2d04563 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AlgorithmIdentifierAsn.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/AttributeAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/AttributeAsn.xml.cs index ad217282851c8c..a25b39a22327c6 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 @@ -119,4 +119,116 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R sequenceReader.ThrowIfNotEmpty(); } } + + [StructLayout(LayoutKind.Sequential)] + internal ref partial struct ValueAttributeAsn + { + internal string AttrType; + internal ReadOnlySpan AttrValues; + + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueAttributeAsn decoded) + { + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); + } + + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueAttributeAsn 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 ValueAttributeAsn decoded) + { + Decode(ref reader, Asn1Tag.Sequence, out decoded); + } + + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueAttributeAsn 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 ValueAttributeAsn decoded) + { + decoded = default; + ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); + + decoded.AttrType = sequenceReader.ReadObjectIdentifier(); + + if (!sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.SetOf)) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + decoded.AttrValues = sequenceReader.ReadEncodedValue(); + + sequenceReader.ThrowIfNotEmpty(); + } + + + internal AttrValuesEnumerable GetAttrValues(AsnEncodingRules ruleSet) + { + return new AttrValuesEnumerable(AttrValues, ruleSet); + } + + internal readonly ref struct AttrValuesEnumerable + { + private readonly ReadOnlySpan _encoded; + private readonly AsnEncodingRules _ruleSet; + + internal AttrValuesEnumerable(ReadOnlySpan encoded, AsnEncodingRules ruleSet) + { + _encoded = encoded; + _ruleSet = ruleSet; + } + + public Enumerator GetEnumerator() => new Enumerator(_encoded, _ruleSet); + + internal ref struct Enumerator + { + private ValueAsnReader _reader; + private ReadOnlySpan _current; + + internal Enumerator(ReadOnlySpan encoded, AsnEncodingRules ruleSet) + { + if (!encoded.IsEmpty) + { + ValueAsnReader outerReader = new ValueAsnReader(encoded, ruleSet); + _reader = outerReader.ReadSetOf(); + outerReader.ThrowIfNotEmpty(); + } + + _current = default; + } + + public ReadOnlySpan Current => _current; + + public bool MoveNext() + { + if (!_reader.HasData) + { + return false; + } + + _current = _reader.ReadEncodedValue(); + return true; + } + } + } + } } 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 66366c549c4323..c8f2f2a4036c9c 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 @@ -8,22 +8,17 @@ namespace System.Security.Cryptography.X509Certificates.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct GeneralSubtreeAsn + file static class SharedGeneralSubtreeAsn { - private static ReadOnlySpan DefaultMinimum => [0x02, 0x01, 0x00]; - - internal System.Security.Cryptography.Asn1.GeneralNameAsn Base; - internal int Minimum; - internal int? Maximum; + internal static ReadOnlySpan DefaultMinimum => [0x02, 0x01, 0x00]; #if DEBUG - static GeneralSubtreeAsn() + static SharedGeneralSubtreeAsn() { GeneralSubtreeAsn decoded = default; ValueAsnReader reader; - reader = new ValueAsnReader(DefaultMinimum, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedGeneralSubtreeAsn.DefaultMinimum, AsnEncodingRules.DER); if (!reader.TryReadInt32(out decoded.Minimum)) { @@ -33,6 +28,14 @@ static GeneralSubtreeAsn() reader.ThrowIfNotEmpty(); } #endif + } + + [StructLayout(LayoutKind.Sequential)] + internal partial struct GeneralSubtreeAsn + { + internal System.Security.Cryptography.Asn1.GeneralNameAsn Base; + internal int Minimum; + internal int? Maximum; internal readonly void Encode(AsnWriter writer) { @@ -51,7 +54,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER, initialCapacity: AsnManagedIntegerDerMaxEncodeSize); tmp.WriteInteger(Minimum); - if (!tmp.EncodedValueEquals(DefaultMinimum)) + if (!tmp.EncodedValueEquals(SharedGeneralSubtreeAsn.DefaultMinimum)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); tmp.CopyTo(writer); @@ -130,7 +133,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultMinimum, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedGeneralSubtreeAsn.DefaultMinimum, AsnEncodingRules.DER); if (!defaultReader.TryReadInt32(out decoded.Minimum)) { diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/OaepParamsAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/OaepParamsAsn.xml.cs index e2b2098b80911e..1bfeabc1e0347a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/OaepParamsAsn.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/OaepParamsAsn.xml.cs @@ -8,39 +8,42 @@ namespace System.Security.Cryptography.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct OaepParamsAsn + file static class SharedOaepParamsAsn { - private static ReadOnlySpan DefaultHashFunc => [0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00]; + internal static ReadOnlySpan DefaultHashFunc => [0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00]; - private static ReadOnlySpan DefaultMaskGenFunc => [0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00]; + internal static ReadOnlySpan DefaultMaskGenFunc => [0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00]; - private static ReadOnlySpan DefaultPSourceFunc => [0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x09, 0x04, 0x00]; - - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashFunc; - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenFunc; - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn PSourceFunc; + internal static ReadOnlySpan DefaultPSourceFunc => [0x30, 0x0D, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x09, 0x04, 0x00]; #if DEBUG - static OaepParamsAsn() + static SharedOaepParamsAsn() { OaepParamsAsn decoded = default; ReadOnlyMemory rebind = default; ValueAsnReader reader; - reader = new ValueAsnReader(DefaultHashFunc, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedOaepParamsAsn.DefaultHashFunc, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashFunc); reader.ThrowIfNotEmpty(); - reader = new ValueAsnReader(DefaultMaskGenFunc, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedOaepParamsAsn.DefaultMaskGenFunc, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.MaskGenFunc); reader.ThrowIfNotEmpty(); - reader = new ValueAsnReader(DefaultPSourceFunc, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedOaepParamsAsn.DefaultPSourceFunc, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.PSourceFunc); reader.ThrowIfNotEmpty(); } #endif + } + + [StructLayout(LayoutKind.Sequential)] + internal partial struct OaepParamsAsn + { + internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashFunc; + internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenFunc; + internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn PSourceFunc; internal readonly void Encode(AsnWriter writer) { @@ -57,7 +60,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER); HashFunc.Encode(tmp); - if (!tmp.EncodedValueEquals(DefaultHashFunc)) + if (!tmp.EncodedValueEquals(SharedOaepParamsAsn.DefaultHashFunc)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); tmp.CopyTo(writer); @@ -71,7 +74,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER); MaskGenFunc.Encode(tmp); - if (!tmp.EncodedValueEquals(DefaultMaskGenFunc)) + if (!tmp.EncodedValueEquals(SharedOaepParamsAsn.DefaultMaskGenFunc)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); tmp.CopyTo(writer); @@ -85,7 +88,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER); PSourceFunc.Encode(tmp); - if (!tmp.EncodedValueEquals(DefaultPSourceFunc)) + if (!tmp.EncodedValueEquals(SharedOaepParamsAsn.DefaultPSourceFunc)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2)); tmp.CopyTo(writer); @@ -150,7 +153,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultHashFunc, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedOaepParamsAsn.DefaultHashFunc, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.HashFunc); } @@ -163,7 +166,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultMaskGenFunc, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedOaepParamsAsn.DefaultMaskGenFunc, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.MaskGenFunc); } @@ -176,7 +179,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultPSourceFunc, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedOaepParamsAsn.DefaultPSourceFunc, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.PSourceFunc); } 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 77496a88650038..0012541c13dbf3 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 @@ -8,28 +8,31 @@ namespace System.Security.Cryptography.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct Pbkdf2Params + file static class SharedPbkdf2Params { - private static ReadOnlySpan DefaultPrf => [0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07, 0x05, 0x00]; - - internal System.Security.Cryptography.Asn1.Pbkdf2SaltChoice Salt; - internal int IterationCount; - internal int? KeyLength; - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn Prf; + internal static ReadOnlySpan DefaultPrf => [0x30, 0x0C, 0x06, 0x08, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x07, 0x05, 0x00]; #if DEBUG - static Pbkdf2Params() + static SharedPbkdf2Params() { Pbkdf2Params decoded = default; ReadOnlyMemory rebind = default; ValueAsnReader reader; - reader = new ValueAsnReader(DefaultPrf, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedPbkdf2Params.DefaultPrf, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.Prf); reader.ThrowIfNotEmpty(); } #endif + } + + [StructLayout(LayoutKind.Sequential)] + internal partial struct Pbkdf2Params + { + internal System.Security.Cryptography.Asn1.Pbkdf2SaltChoice Salt; + internal int IterationCount; + internal int? KeyLength; + internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn Prf; internal readonly void Encode(AsnWriter writer) { @@ -54,7 +57,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER); Prf.Encode(tmp); - if (!tmp.EncodedValueEquals(DefaultPrf)) + if (!tmp.EncodedValueEquals(SharedPbkdf2Params.DefaultPrf)) { tmp.CopyTo(writer); } @@ -136,7 +139,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultPrf, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedPbkdf2Params.DefaultPrf, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.Prf); } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs12/MacData.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs12/MacData.xml.cs index 7c4e07d3702975..d6c26ba509af78 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs12/MacData.xml.cs +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/Pkcs12/MacData.xml.cs @@ -8,22 +8,17 @@ namespace System.Security.Cryptography.Asn1.Pkcs12 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct MacData + file static class SharedMacData { - private static ReadOnlySpan DefaultIterationCount => [0x02, 0x01, 0x01]; - - internal System.Security.Cryptography.Asn1.DigestInfoAsn Mac; - internal ReadOnlyMemory MacSalt; - internal int IterationCount; + internal static ReadOnlySpan DefaultIterationCount => [0x02, 0x01, 0x01]; #if DEBUG - static MacData() + static SharedMacData() { MacData decoded = default; ValueAsnReader reader; - reader = new ValueAsnReader(DefaultIterationCount, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedMacData.DefaultIterationCount, AsnEncodingRules.DER); if (!reader.TryReadInt32(out decoded.IterationCount)) { @@ -33,6 +28,14 @@ static MacData() reader.ThrowIfNotEmpty(); } #endif + } + + [StructLayout(LayoutKind.Sequential)] + internal partial struct MacData + { + internal System.Security.Cryptography.Asn1.DigestInfoAsn Mac; + internal ReadOnlyMemory MacSalt; + internal int IterationCount; internal readonly void Encode(AsnWriter writer) { @@ -52,7 +55,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER, initialCapacity: AsnManagedIntegerDerMaxEncodeSize); tmp.WriteInteger(IterationCount); - if (!tmp.EncodedValueEquals(DefaultIterationCount)) + if (!tmp.EncodedValueEquals(SharedMacData.DefaultIterationCount)) { tmp.CopyTo(writer); } @@ -131,7 +134,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultIterationCount, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedMacData.DefaultIterationCount, AsnEncodingRules.DER); if (!defaultReader.TryReadInt32(out decoded.IterationCount)) { 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 b80004f5efa50c..9dede0a3d7d312 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 @@ -61,4 +61,60 @@ internal RSASignaturePadding GetSignaturePadding( return RSASignaturePadding.Pss; } } + + internal ref partial struct ValuePssParamsAsn + { + 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.HasParameters) + { + throw new CryptographicException(SR.Cryptography_Pkcs_InvalidSignatureParameters); + } + + ValueAlgorithmIdentifierAsn.Decode( + MaskGenAlgorithm.Parameters, + AsnEncodingRules.DER, + out ValueAlgorithmIdentifierAsn mgfParams); + + 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; + } + } } 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 b80c54c49c7324..e3e3f32adf9f51 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/PssParamsAsn.xml @@ -2,11 +2,12 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="both"> - - + + - \ No newline at end of file + 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 4c952f6a3f49dc..43e8ff1f4c64ad 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 @@ -8,38 +8,32 @@ namespace System.Security.Cryptography.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct PssParamsAsn + file static class SharedPssParamsAsn { - private static ReadOnlySpan DefaultHashAlgorithm => [0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00]; + internal static ReadOnlySpan DefaultHashAlgorithm => [0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00]; - private static ReadOnlySpan DefaultMaskGenAlgorithm => [0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00]; + internal static ReadOnlySpan DefaultMaskGenAlgorithm => [0x30, 0x16, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x08, 0x30, 0x09, 0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05, 0x00]; - private static ReadOnlySpan DefaultSaltLength => [0x02, 0x01, 0x14]; + internal static ReadOnlySpan DefaultSaltLength => [0x02, 0x01, 0x14]; - private static ReadOnlySpan DefaultTrailerField => [0x02, 0x01, 0x01]; - - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm; - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenAlgorithm; - internal int SaltLength; - internal int TrailerField; + internal static ReadOnlySpan DefaultTrailerField => [0x02, 0x01, 0x01]; #if DEBUG - static PssParamsAsn() + static SharedPssParamsAsn() { PssParamsAsn decoded = default; ReadOnlyMemory rebind = default; ValueAsnReader reader; - reader = new ValueAsnReader(DefaultHashAlgorithm, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedPssParamsAsn.DefaultHashAlgorithm, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashAlgorithm); reader.ThrowIfNotEmpty(); - reader = new ValueAsnReader(DefaultMaskGenAlgorithm, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedPssParamsAsn.DefaultMaskGenAlgorithm, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.MaskGenAlgorithm); reader.ThrowIfNotEmpty(); - reader = new ValueAsnReader(DefaultSaltLength, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedPssParamsAsn.DefaultSaltLength, AsnEncodingRules.DER); if (!reader.TryReadInt32(out decoded.SaltLength)) { @@ -48,7 +42,7 @@ static PssParamsAsn() reader.ThrowIfNotEmpty(); - reader = new ValueAsnReader(DefaultTrailerField, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedPssParamsAsn.DefaultTrailerField, AsnEncodingRules.DER); if (!reader.TryReadInt32(out decoded.TrailerField)) { @@ -58,6 +52,15 @@ static PssParamsAsn() reader.ThrowIfNotEmpty(); } #endif + } + + [StructLayout(LayoutKind.Sequential)] + internal partial struct PssParamsAsn + { + internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm; + internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn MaskGenAlgorithm; + internal int SaltLength; + internal int TrailerField; internal readonly void Encode(AsnWriter writer) { @@ -74,7 +77,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER); HashAlgorithm.Encode(tmp); - if (!tmp.EncodedValueEquals(DefaultHashAlgorithm)) + if (!tmp.EncodedValueEquals(SharedPssParamsAsn.DefaultHashAlgorithm)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); tmp.CopyTo(writer); @@ -88,7 +91,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER); MaskGenAlgorithm.Encode(tmp); - if (!tmp.EncodedValueEquals(DefaultMaskGenAlgorithm)) + if (!tmp.EncodedValueEquals(SharedPssParamsAsn.DefaultMaskGenAlgorithm)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 1)); tmp.CopyTo(writer); @@ -103,7 +106,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER, initialCapacity: AsnManagedIntegerDerMaxEncodeSize); tmp.WriteInteger(SaltLength); - if (!tmp.EncodedValueEquals(DefaultSaltLength)) + if (!tmp.EncodedValueEquals(SharedPssParamsAsn.DefaultSaltLength)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 2)); tmp.CopyTo(writer); @@ -118,7 +121,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER, initialCapacity: AsnManagedIntegerDerMaxEncodeSize); tmp.WriteInteger(TrailerField); - if (!tmp.EncodedValueEquals(DefaultTrailerField)) + if (!tmp.EncodedValueEquals(SharedPssParamsAsn.DefaultTrailerField)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 3)); tmp.CopyTo(writer); @@ -183,7 +186,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultHashAlgorithm, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedPssParamsAsn.DefaultHashAlgorithm, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.HashAlgorithm); } @@ -196,7 +199,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultMaskGenAlgorithm, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedPssParamsAsn.DefaultMaskGenAlgorithm, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.MaskGenAlgorithm); } @@ -214,7 +217,136 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultSaltLength, AsnEncodingRules.DER); + 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); + } + + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValuePssParamsAsn 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 ValuePssParamsAsn decoded) + { + Decode(ref reader, Asn1Tag.Sequence, out decoded); + } + + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValuePssParamsAsn 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 ValuePssParamsAsn 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.ValueAlgorithmIdentifierAsn.Decode(ref explicitReader, out decoded.HashAlgorithm); + explicitReader.ThrowIfNotEmpty(); + } + else + { + defaultReader = new ValueAsnReader(SharedPssParamsAsn.DefaultHashAlgorithm, AsnEncodingRules.DER); + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref defaultReader, 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.ValueAlgorithmIdentifierAsn.Decode(ref explicitReader, out decoded.MaskGenAlgorithm); + explicitReader.ThrowIfNotEmpty(); + } + else + { + defaultReader = new ValueAsnReader(SharedPssParamsAsn.DefaultMaskGenAlgorithm, AsnEncodingRules.DER); + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref defaultReader, 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)) { @@ -237,7 +369,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultTrailerField, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedPssParamsAsn.DefaultTrailerField, AsnEncodingRules.DER); if (!defaultReader.TryReadInt32(out decoded.TrailerField)) { diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml index 1fa5606465e4ca..8f749cb9c0a6f0 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.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/SubjectPublicKeyInfoAsn.xml.cs b/src/libraries/Common/src/System/Security/Cryptography/Asn1/SubjectPublicKeyInfoAsn.xml.cs index b738b0690a8a06..80ce6bb17b408e 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 @@ -86,6 +86,71 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } + sequenceReader.ThrowIfNotEmpty(); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal ref partial struct ValueSubjectPublicKeyInfoAsn + { + internal System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn Algorithm; + internal ReadOnlySpan SubjectPublicKey; + + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueSubjectPublicKeyInfoAsn decoded) + { + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); + } + + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueSubjectPublicKeyInfoAsn 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 ValueSubjectPublicKeyInfoAsn decoded) + { + Decode(ref reader, Asn1Tag.Sequence, out decoded); + } + + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueSubjectPublicKeyInfoAsn 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 ValueSubjectPublicKeyInfoAsn decoded) + { + decoded = default; + ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); + ReadOnlySpan tmpSpan; + + System.Security.Cryptography.Asn1.ValueAlgorithmIdentifierAsn.Decode(ref sequenceReader, out decoded.Algorithm); + + if (sequenceReader.TryReadPrimitiveBitString(out _, out tmpSpan)) + { + decoded.SubjectPublicKey = tmpSpan; + } + else + { + decoded.SubjectPublicKey = sequenceReader.ReadBitString(out _); + } + + sequenceReader.ThrowIfNotEmpty(); } } diff --git a/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml b/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml index 0bf07c6d172380..457a2864dd625a 100644 --- a/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml +++ b/src/libraries/Common/src/System/Security/Cryptography/Asn1/X509ExtensionAsn.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Asn1" + emitType="both"> + + + Error, unknown ValueFieldDef node [] + + + + + + + + + + + + + + + + + internal ReadOnlySpan<byte> ; + internal bool Has; + + + internal ReadOnlySpan<byte> ; + internal bool Has; + + + internal ReadOnlySpan<byte> ; + internal bool Has; + + + internal ReadOnlySpan<byte> ; + internal bool Has; + + + internal ReadOnlySpan<byte> ; + internal bool Has; + + + + internal ; + internal bool Has; + + + internal ? ; + + + internal ReadOnlySpan<byte> ; + internal bool Has; + + + + + + + + + + + + + + + + + + + tmp; + .Decode(ref , out tmp); + = tmp; + + + .Decode(ref , out ); + + + + + + + + + + tmp; + .Decode(ref , out tmp); + = tmp; + + + .Decode(ref , out ); + + + + + + + + + = .ReadEncodedValue(); + + + + + + + + + if (!.PeekTag().HasSameClassAndValue()) + { + throw new CryptographicException(); + } + + = .ReadEncodedValue(); + + = .ReadEncodedValue(); + + + + + + + + + + = .ReadIntegerBytes(); + + + + + + + + + + if (.TryReadPrimitiveBitString(out _, out tmpSpan)) + { + = tmpSpan; + } + else + { + = .ReadBitString(out _); + } + + + + + + + + + + + if (.TryReadPrimitiveOctetString(out tmpSpan)) + { + = tmpSpan; + } + else + { + = .ReadOctetString(); + } + + + + + + + + + + + + Asn1Tag.SetOf + Asn1Tag.Sequence + + + + + if (!.PeekTag().HasSameClassAndValue()) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + + + decoded. = .ReadEncodedValue(); + + + + + + + + + decoded.Has = true; + + + + + + + + else if (tag.HasSameClassAndValue()) + { + explicitReader = reader.ReadSequence(); + explicitReader.ThrowIfNotEmpty(); + } + + else if (tag.HasSameClassAndValue()) + { + } + + + + + + + if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue()) + { + explicitReader = sequenceReader.ReadSequence(); + explicitReader.ThrowIfNotEmpty(); + } + + + + if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue()) + { + } + + + + if (sequenceReader.HasData) + { + } + + + + if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue()) + { + } + + + + + + explicitReader = sequenceReader.ReadSequence(); + explicitReader.ThrowIfNotEmpty(); + + + + + + + + + + + + + + + + else + { + defaultReader = new ValueAsnReader(, AsnEncodingRules.DER); + } + + + + + 1 + 0 + + + + + + + + + SetOf + Sequence + + + + + + ReadOnlySpan<byte> + + + + + internal Enumerable (AsnEncodingRules ruleSet) + { + return new Enumerable(, ruleSet); + } + + internal readonly ref struct Enumerable + { + private readonly ReadOnlySpan<byte> _encoded; + private readonly AsnEncodingRules _ruleSet; + + internal Enumerable(ReadOnlySpan<byte> encoded, AsnEncodingRules ruleSet) + { + _encoded = encoded; + _ruleSet = ruleSet; + } + + public Enumerator GetEnumerator() => new Enumerator(_encoded, _ruleSet); + + internal ref struct Enumerator + { + private ValueAsnReader _reader; + private _current; + + internal Enumerator(ReadOnlySpan<byte> encoded, AsnEncodingRules ruleSet) + { + if (!encoded.IsEmpty) + { + ValueAsnReader outerReader = new ValueAsnReader(encoded, ruleSet); + _reader = outerReader.Read(); + outerReader.ThrowIfNotEmpty(); + } + + _current = default; + } + + public Current => _current; + + public bool MoveNext() + { + if (!_reader.HasData) + { + return false; + } + + .Decode(ref _reader, out _current); + _current = _reader.ReadEncodedValue(); + return true; + } + } + } + + + + + + + + + diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EssCertIdV2.xml.cs b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EssCertIdV2.xml.cs index 68c4fce2aaa806..91c6c3cbc83f46 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EssCertIdV2.xml.cs +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/EssCertIdV2.xml.cs @@ -8,27 +8,30 @@ namespace System.Security.Cryptography.Pkcs.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct EssCertIdV2 + file static class SharedEssCertIdV2 { - private static ReadOnlySpan DefaultHashAlgorithm => [0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01]; - - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm; - internal ReadOnlyMemory Hash; - internal System.Security.Cryptography.Pkcs.Asn1.CadesIssuerSerial? IssuerSerial; + internal static ReadOnlySpan DefaultHashAlgorithm => [0x30, 0x0B, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01]; #if DEBUG - static EssCertIdV2() + static SharedEssCertIdV2() { EssCertIdV2 decoded = default; ReadOnlyMemory rebind = default; ValueAsnReader reader; - reader = new ValueAsnReader(DefaultHashAlgorithm, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedEssCertIdV2.DefaultHashAlgorithm, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref reader, rebind, out decoded.HashAlgorithm); reader.ThrowIfNotEmpty(); } #endif + } + + [StructLayout(LayoutKind.Sequential)] + internal partial struct EssCertIdV2 + { + internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn HashAlgorithm; + internal ReadOnlyMemory Hash; + internal System.Security.Cryptography.Pkcs.Asn1.CadesIssuerSerial? IssuerSerial; internal readonly void Encode(AsnWriter writer) { @@ -45,7 +48,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER); HashAlgorithm.Encode(tmp); - if (!tmp.EncodedValueEquals(DefaultHashAlgorithm)) + if (!tmp.EncodedValueEquals(SharedEssCertIdV2.DefaultHashAlgorithm)) { tmp.CopyTo(writer); } @@ -115,7 +118,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultHashAlgorithm, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedEssCertIdV2.DefaultHashAlgorithm, AsnEncodingRules.DER); System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn.Decode(ref defaultReader, rebind, out decoded.HashAlgorithm); } diff --git a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.xml b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.xml index e0d6703b9c0782..3f0c647f8b8471 100644 --- a/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.xml +++ b/src/libraries/System.Security.Cryptography.Pkcs/src/System/Security/Cryptography/Pkcs/Asn1/MessageImprint.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.Pkcs.Asn1" + emitType="both"> - + 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 a7f4011fb0bef0..1a71b5f83937ff 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 @@ -9,11 +9,26 @@ namespace System.Security.Cryptography.Pkcs.Asn1 { + file static class SharedRfc3161TstInfo + { + internal static ReadOnlySpan DefaultOrdering => [0x01, 0x01, 0x00]; + +#if DEBUG + static SharedRfc3161TstInfo() + { + Rfc3161TstInfo decoded = default; + ValueAsnReader reader; + + reader = new ValueAsnReader(SharedRfc3161TstInfo.DefaultOrdering, AsnEncodingRules.DER); + decoded.Ordering = reader.ReadBoolean(); + reader.ThrowIfNotEmpty(); + } +#endif + } + [StructLayout(LayoutKind.Sequential)] internal partial struct Rfc3161TstInfo { - private static ReadOnlySpan DefaultOrdering => [0x01, 0x01, 0x00]; - internal int Version; internal string Policy; internal System.Security.Cryptography.Pkcs.Asn1.MessageImprint MessageImprint; @@ -25,18 +40,6 @@ internal partial struct Rfc3161TstInfo internal System.Security.Cryptography.Asn1.GeneralNameAsn? Tsa; internal System.Security.Cryptography.Asn1.X509ExtensionAsn[]? Extensions; -#if DEBUG - static Rfc3161TstInfo() - { - Rfc3161TstInfo decoded = default; - ValueAsnReader reader; - - reader = new ValueAsnReader(DefaultOrdering, AsnEncodingRules.DER); - decoded.Ordering = reader.ReadBoolean(); - reader.ThrowIfNotEmpty(); - } -#endif - internal readonly void Encode(AsnWriter writer) { Encode(writer, Asn1Tag.Sequence); @@ -71,7 +74,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER, initialCapacity: AsnBoolDerEncodeSize); tmp.WriteBoolean(Ordering); - if (!tmp.EncodedValueEquals(DefaultOrdering)) + if (!tmp.EncodedValueEquals(SharedRfc3161TstInfo.DefaultOrdering)) { tmp.CopyTo(writer); } @@ -183,7 +186,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultOrdering, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedRfc3161TstInfo.DefaultOrdering, AsnEncodingRules.DER); decoded.Ordering = defaultReader.ReadBoolean(); } @@ -227,6 +230,125 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } + sequenceReader.ThrowIfNotEmpty(); + } + } + + [StructLayout(LayoutKind.Sequential)] + internal ref partial struct ValueRfc3161TstInfo + { + internal int Version; + internal string Policy; + internal System.Security.Cryptography.Pkcs.Asn1.ValueMessageImprint MessageImprint; + internal ReadOnlySpan SerialNumber; + 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 static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueRfc3161TstInfo decoded) + { + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); + } + + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueRfc3161TstInfo 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 ValueRfc3161TstInfo decoded) + { + Decode(ref reader, Asn1Tag.Sequence, out decoded); + } + + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueRfc3161TstInfo 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 ValueRfc3161TstInfo decoded) + { + decoded = default; + ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); + ValueAsnReader explicitReader; + ValueAsnReader defaultReader; + + + if (!sequenceReader.TryReadInt32(out decoded.Version)) + { + sequenceReader.ThrowIfNotEmpty(); + } + + decoded.Policy = sequenceReader.ReadObjectIdentifier(); + System.Security.Cryptography.Pkcs.Asn1.ValueMessageImprint.Decode(ref sequenceReader, out decoded.MessageImprint); + decoded.SerialNumber = sequenceReader.ReadIntegerBytes(); + decoded.GenTime = sequenceReader.ReadGeneralizedTime(); + + if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Sequence)) + { + System.Security.Cryptography.Pkcs.Asn1.Rfc3161Accuracy tmpAccuracy; + System.Security.Cryptography.Pkcs.Asn1.Rfc3161Accuracy.Decode(ref sequenceReader, out tmpAccuracy); + decoded.Accuracy = tmpAccuracy; + + } + + + if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Boolean)) + { + decoded.Ordering = sequenceReader.ReadBoolean(); + } + else + { + defaultReader = new ValueAsnReader(SharedRfc3161TstInfo.DefaultOrdering, AsnEncodingRules.DER); + decoded.Ordering = defaultReader.ReadBoolean(); + } + + + if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(Asn1Tag.Integer)) + { + decoded.Nonce = sequenceReader.ReadIntegerBytes(); + decoded.HasNonce = true; + } + + + if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0))) + { + explicitReader = sequenceReader.ReadSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); + decoded.Tsa = explicitReader.ReadEncodedValue(); + decoded.HasTsa = true; + explicitReader.ThrowIfNotEmpty(); + } + + + if (sequenceReader.HasData && sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 1))) + { + decoded.Extensions = sequenceReader.ReadEncodedValue(); + decoded.HasExtensions = true; + } + + sequenceReader.ThrowIfNotEmpty(); } } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/BasicConstraintsAsn.xml.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/BasicConstraintsAsn.xml.cs index b69516ee61cdc6..38a1453f3e2966 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/BasicConstraintsAsn.xml.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/BasicConstraintsAsn.xml.cs @@ -8,25 +8,28 @@ namespace System.Security.Cryptography.X509Certificates.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct BasicConstraintsAsn + file static class SharedBasicConstraintsAsn { - private static ReadOnlySpan DefaultCA => [0x01, 0x01, 0x00]; - - internal bool CA; - internal int? PathLengthConstraint; + internal static ReadOnlySpan DefaultCA => [0x01, 0x01, 0x00]; #if DEBUG - static BasicConstraintsAsn() + static SharedBasicConstraintsAsn() { BasicConstraintsAsn decoded = default; ValueAsnReader reader; - reader = new ValueAsnReader(DefaultCA, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedBasicConstraintsAsn.DefaultCA, AsnEncodingRules.DER); decoded.CA = reader.ReadBoolean(); reader.ThrowIfNotEmpty(); } #endif + } + + [StructLayout(LayoutKind.Sequential)] + internal partial struct BasicConstraintsAsn + { + internal bool CA; + internal int? PathLengthConstraint; internal readonly void Encode(AsnWriter writer) { @@ -44,7 +47,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER, initialCapacity: AsnBoolDerEncodeSize); tmp.WriteBoolean(CA); - if (!tmp.EncodedValueEquals(DefaultCA)) + if (!tmp.EncodedValueEquals(SharedBasicConstraintsAsn.DefaultCA)) { tmp.CopyTo(writer); } @@ -110,7 +113,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, o } else { - defaultReader = new ValueAsnReader(DefaultCA, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedBasicConstraintsAsn.DefaultCA, AsnEncodingRules.DER); decoded.CA = defaultReader.ReadBoolean(); } diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/CertificationRequestInfoAsn.xml b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/CertificationRequestInfoAsn.xml index 41cd3579d1ccf5..d6b9130e1dbf9c 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/CertificationRequestInfoAsn.xml +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/CertificationRequestInfoAsn.xml @@ -2,7 +2,8 @@ + namespace="System.Security.Cryptography.X509Certificates.Asn1" + emitType="both"> - - - + + + - \ No newline at end of file + 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 403949afeac484..12ac6712256a99 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 @@ -132,4 +132,125 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R sequenceReader.ThrowIfNotEmpty(); } } + + [StructLayout(LayoutKind.Sequential)] + internal ref partial struct ValueCertificationRequestInfoAsn + { + internal System.Numerics.BigInteger Version; + internal ReadOnlySpan Subject; + internal System.Security.Cryptography.Asn1.ValueSubjectPublicKeyInfoAsn SubjectPublicKeyInfo; + internal ReadOnlySpan Attributes; + + internal static void Decode(ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueCertificationRequestInfoAsn decoded) + { + Decode(Asn1Tag.Sequence, encoded, ruleSet, out decoded); + } + + internal static void Decode(Asn1Tag expectedTag, ReadOnlySpan encoded, AsnEncodingRules ruleSet, out ValueCertificationRequestInfoAsn 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 ValueCertificationRequestInfoAsn decoded) + { + Decode(ref reader, Asn1Tag.Sequence, out decoded); + } + + internal static void Decode(scoped ref ValueAsnReader reader, Asn1Tag expectedTag, out ValueCertificationRequestInfoAsn 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 ValueCertificationRequestInfoAsn decoded) + { + decoded = default; + ValueAsnReader sequenceReader = reader.ReadSequence(expectedTag); + + decoded.Version = sequenceReader.ReadInteger(); + if (!sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag((UniversalTagNumber)16))) + { + throw new CryptographicException(); + } + + decoded.Subject = sequenceReader.ReadEncodedValue(); + System.Security.Cryptography.Asn1.ValueSubjectPublicKeyInfoAsn.Decode(ref sequenceReader, out decoded.SubjectPublicKeyInfo); + + if (!sequenceReader.PeekTag().HasSameClassAndValue(new Asn1Tag(TagClass.ContextSpecific, 0))) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } + + decoded.Attributes = sequenceReader.ReadEncodedValue(); + + 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/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/TbsCertificateAsn.xml.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/TbsCertificateAsn.xml.cs index 0f0b267b23639b..4242feccf97118 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/TbsCertificateAsn.xml.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/Asn1/TbsCertificateAsn.xml.cs @@ -9,29 +9,17 @@ namespace System.Security.Cryptography.X509Certificates.Asn1 { - [StructLayout(LayoutKind.Sequential)] - internal partial struct TbsCertificateAsn + file static class SharedTbsCertificateAsn { - private static ReadOnlySpan DefaultVersion => [0x02, 0x01, 0x00]; - - internal int Version; - internal ReadOnlyMemory SerialNumber; - internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn SignatureAlgorithm; - internal ReadOnlyMemory Issuer; - internal System.Security.Cryptography.X509Certificates.Asn1.ValidityAsn Validity; - internal ReadOnlyMemory Subject; - internal System.Security.Cryptography.Asn1.SubjectPublicKeyInfoAsn SubjectPublicKeyInfo; - internal ReadOnlyMemory? IssuerUniqueId; - internal ReadOnlyMemory? SubjectUniqueId; - internal System.Security.Cryptography.Asn1.X509ExtensionAsn[]? Extensions; + internal static ReadOnlySpan DefaultVersion => [0x02, 0x01, 0x00]; #if DEBUG - static TbsCertificateAsn() + static SharedTbsCertificateAsn() { TbsCertificateAsn decoded = default; ValueAsnReader reader; - reader = new ValueAsnReader(DefaultVersion, AsnEncodingRules.DER); + reader = new ValueAsnReader(SharedTbsCertificateAsn.DefaultVersion, AsnEncodingRules.DER); if (!reader.TryReadInt32(out decoded.Version)) { @@ -41,6 +29,21 @@ static TbsCertificateAsn() reader.ThrowIfNotEmpty(); } #endif + } + + [StructLayout(LayoutKind.Sequential)] + internal partial struct TbsCertificateAsn + { + internal int Version; + internal ReadOnlyMemory SerialNumber; + internal System.Security.Cryptography.Asn1.AlgorithmIdentifierAsn SignatureAlgorithm; + internal ReadOnlyMemory Issuer; + internal System.Security.Cryptography.X509Certificates.Asn1.ValidityAsn Validity; + internal ReadOnlyMemory Subject; + internal System.Security.Cryptography.Asn1.SubjectPublicKeyInfoAsn SubjectPublicKeyInfo; + internal ReadOnlyMemory? IssuerUniqueId; + internal ReadOnlyMemory? SubjectUniqueId; + internal System.Security.Cryptography.Asn1.X509ExtensionAsn[]? Extensions; internal readonly void Encode(AsnWriter writer) { @@ -58,7 +61,7 @@ internal readonly void Encode(AsnWriter writer, Asn1Tag tag) AsnWriter tmp = new AsnWriter(AsnEncodingRules.DER, initialCapacity: AsnManagedIntegerDerMaxEncodeSize); tmp.WriteInteger(Version); - if (!tmp.EncodedValueEquals(DefaultVersion)) + if (!tmp.EncodedValueEquals(SharedTbsCertificateAsn.DefaultVersion)) { writer.PushSequence(new Asn1Tag(TagClass.ContextSpecific, 0)); tmp.CopyTo(writer); @@ -197,7 +200,7 @@ private static void DecodeCore(ref ValueAsnReader reader, Asn1Tag expectedTag, R } else { - defaultReader = new ValueAsnReader(DefaultVersion, AsnEncodingRules.DER); + defaultReader = new ValueAsnReader(SharedTbsCertificateAsn.DefaultVersion, AsnEncodingRules.DER); if (!defaultReader.TryReadInt32(out decoded.Version)) { diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.Load.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.Load.cs index 57a102169ad5c4..9644f1bc90e86c 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.Load.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/CertificateRequest.Load.cs @@ -149,135 +149,141 @@ private static unsafe CertificateRequest LoadSigningRequest( outer.ThrowIfNotEmpty(); } - fixed (byte* p10ptr = pkcs10) + ReadOnlySpan encodedRequestInfo = pkcs10Asn.PeekEncodedValue(); + ValueCertificationRequestInfoAsn requestInfo; + ValueAlgorithmIdentifierAsn algorithmIdentifier; + ReadOnlySpan signature; + int signatureUnusedBitCount; + + ValueCertificationRequestInfoAsn.Decode(ref pkcs10Asn, out requestInfo); + ValueAlgorithmIdentifierAsn.Decode(ref pkcs10Asn, out algorithmIdentifier); + + if (!pkcs10Asn.TryReadPrimitiveBitString(out signatureUnusedBitCount, out signature)) { - using (PointerMemoryManager manager = new PointerMemoryManager(p10ptr, encodedLength)) - { - ReadOnlyMemory rebind = manager.Memory; - ReadOnlySpan encodedRequestInfo = pkcs10Asn.PeekEncodedValue(); - CertificationRequestInfoAsn requestInfo; - AlgorithmIdentifierAsn algorithmIdentifier; - ReadOnlySpan signature; - int signatureUnusedBitCount; + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } - CertificationRequestInfoAsn.Decode(ref pkcs10Asn, rebind, out requestInfo); - AlgorithmIdentifierAsn.Decode(ref pkcs10Asn, rebind, out algorithmIdentifier); + pkcs10Asn.ThrowIfNotEmpty(); - if (!pkcs10Asn.TryReadPrimitiveBitString(out signatureUnusedBitCount, out signature)) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); - } + if (requestInfo.Version < 0) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); + } - pkcs10Asn.ThrowIfNotEmpty(); + // They haven't bumped from v0 to v1 as of 2022. + const int MaxSupportedVersion = 0; - if (requestInfo.Version < 0) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); - } + if (requestInfo.Version != MaxSupportedVersion) + { + throw new CryptographicException( + SR.Format( + SR.Cryptography_CertReq_Load_VersionTooNew, + requestInfo.Version, + MaxSupportedVersion)); + } + + PublicKey publicKey = PublicKey.DecodeSubjectPublicKeyInfo(ref requestInfo.SubjectPublicKeyInfo); + + if (!skipSignatureValidation) + { + // None of the supported signature algorithms support signatures that are not full bytes. + // So, shortcut the verification on the bit length + if (signatureUnusedBitCount != 0 || + !VerifyX509Signature(encodedRequestInfo, signature, publicKey, ref algorithmIdentifier)) + { + throw new CryptographicException(SR.Cryptography_CertReq_SignatureVerificationFailed); + } + } + + X500DistinguishedName subject = new X500DistinguishedName(requestInfo.Subject); - // They haven't bumped from v0 to v1 as of 2022. - const int MaxSupportedVersion = 0; + req = new CertificateRequest( + subject, + publicKey, + signerHashAlgorithm, + signerSignaturePadding); - if (requestInfo.Version != MaxSupportedVersion) + bool foundCertExt = false; + + foreach (ValueAttributeAsn attr in requestInfo.GetAttributes(AsnEncodingRules.DER)) + { + if (attr.AttrType == Oids.Pkcs9ExtensionRequest) + { + if (foundCertExt) { throw new CryptographicException( - SR.Format( - SR.Cryptography_CertReq_Load_VersionTooNew, - requestInfo.Version, - MaxSupportedVersion)); + SR.Cryptography_CertReq_Load_DuplicateExtensionRequests); } - PublicKey publicKey = PublicKey.DecodeSubjectPublicKeyInfo(ref requestInfo.SubjectPublicKeyInfo); + foundCertExt = true; - if (!skipSignatureValidation) + scoped ReadOnlySpan firstAttrValue = default; + bool foundAttrValue = false; + + foreach (ReadOnlySpan values in attr.GetAttrValues(AsnEncodingRules.DER)) { - // None of the supported signature algorithms support signatures that are not full bytes. - // So, shortcut the verification on the bit length - if (signatureUnusedBitCount != 0 || - !VerifyX509Signature(encodedRequestInfo, signature, publicKey, algorithmIdentifier)) + if (foundAttrValue) { - throw new CryptographicException(SR.Cryptography_CertReq_SignatureVerificationFailed); + throw new CryptographicException( + SR.Cryptography_CertReq_Load_DuplicateExtensionRequests); } + + firstAttrValue = values; + foundAttrValue = true; } - X500DistinguishedName subject = new X500DistinguishedName(requestInfo.Subject.Span); + if (!foundAttrValue) + { + throw new CryptographicException(SR.Cryptography_CertReq_Load_DuplicateExtensionRequests); + } - req = new CertificateRequest( - subject, - publicKey, - signerHashAlgorithm, - signerSignaturePadding); + ValueAsnReader extsReader = new ValueAsnReader( + firstAttrValue, + AsnEncodingRules.DER); + + ValueAsnReader exts = extsReader.ReadSequence(); + extsReader.ThrowIfNotEmpty(); - if (requestInfo.Attributes is not null) + // Minimum length is 1, so do..while + do { - bool foundCertExt = false; + ValueX509ExtensionAsn.Decode(ref exts, out ValueX509ExtensionAsn extAsn); - foreach (AttributeAsn attr in requestInfo.Attributes) + if (unsafeLoadCertificateExtensions) { - if (attr.AttrType == Oids.Pkcs9ExtensionRequest) + X509Extension ext = new X509Extension( + extAsn.ExtnId, + extAsn.ExtnValue, + extAsn.Critical); + + X509Extension? rich = + X509Certificate2.CreateCustomExtensionIfAny(extAsn.ExtnId); + + if (rich is not null) { - if (foundCertExt) - { - throw new CryptographicException( - SR.Cryptography_CertReq_Load_DuplicateExtensionRequests); - } - - foundCertExt = true; - - if (attr.AttrValues.Length != 1) - { - throw new CryptographicException( - SR.Cryptography_CertReq_Load_DuplicateExtensionRequests); - } - - ValueAsnReader extsReader = new ValueAsnReader( - attr.AttrValues[0].Span, - AsnEncodingRules.DER); - - ValueAsnReader exts = extsReader.ReadSequence(); - extsReader.ThrowIfNotEmpty(); - - // Minimum length is 1, so do..while - do - { - X509ExtensionAsn.Decode(ref exts, rebind, out X509ExtensionAsn extAsn); - - if (unsafeLoadCertificateExtensions) - { - X509Extension ext = new X509Extension( - extAsn.ExtnId, - extAsn.ExtnValue.Span, - extAsn.Critical); - - X509Extension? rich = - X509Certificate2.CreateCustomExtensionIfAny(extAsn.ExtnId); - - if (rich is not null) - { - rich.CopyFrom(ext); - req.CertificateExtensions.Add(rich); - } - else - { - req.CertificateExtensions.Add(ext); - } - } - } while (exts.HasData); + rich.CopyFrom(ext); + req.CertificateExtensions.Add(rich); } else { - if (attr.AttrValues.Length == 0) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); - } - - foreach (ReadOnlyMemory val in attr.AttrValues) - { - req.OtherRequestAttributes.Add( - new AsnEncodedData(attr.AttrType, val.Span)); - } + req.CertificateExtensions.Add(ext); } } + } while (exts.HasData); + } + else + { + bool anyAttrValues = false; + + foreach (ReadOnlySpan val in attr.GetAttrValues(AsnEncodingRules.DER)) + { + req.OtherRequestAttributes.Add(new AsnEncodedData(attr.AttrType, val)); + anyAttrValues = true; + } + + if (!anyAttrValues) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding); } } } @@ -295,7 +301,7 @@ private static bool VerifyX509Signature( ReadOnlySpan toBeSigned, ReadOnlySpan signature, PublicKey publicKey, - AlgorithmIdentifierAsn algorithmIdentifier) + ref readonly ValueAlgorithmIdentifierAsn algorithmIdentifier) { RSA? rsa = publicKey.GetRSAPublicKey(); ECDsa? ecdsa = publicKey.GetECDsaPublicKey(); @@ -308,14 +314,15 @@ private static bool VerifyX509Signature( if (algorithmIdentifier.Algorithm == Oids.RsaPss) { - if (rsa is null || !algorithmIdentifier.Parameters.HasValue) + if (rsa is null || !algorithmIdentifier.HasParameters) { return false; } - PssParamsAsn pssParams = PssParamsAsn.Decode( - algorithmIdentifier.Parameters.GetValueOrDefault(), - AsnEncodingRules.DER); + ValuePssParamsAsn.Decode( + algorithmIdentifier.Parameters, + AsnEncodingRules.DER, + out ValuePssParamsAsn pssParams); RSASignaturePadding padding = pssParams.GetSignaturePadding(); hashAlg = HashAlgorithmName.FromOid(pssParams.HashAlgorithm.Algorithm); diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/PublicKey.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/PublicKey.cs index 2c3d2d8875cf59..e4c850bcb5b3ea 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/PublicKey.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/PublicKey.cs @@ -451,36 +451,32 @@ internal AsnWriter EncodeSubjectPublicKeyInfo() return writer; } - private static unsafe int DecodeSubjectPublicKeyInfo( + private static int DecodeSubjectPublicKeyInfo( ReadOnlySpan source, out Oid oid, out AsnEncodedData? parameters, out AsnEncodedData keyValue) { - fixed (byte* ptr = &MemoryMarshal.GetReference(source)) - using (MemoryManager manager = new PointerMemoryManager(ptr, source.Length)) - { - ValueAsnReader reader = new ValueAsnReader(source, AsnEncodingRules.DER); + ValueAsnReader reader = new ValueAsnReader(source, AsnEncodingRules.DER); - int read; - SubjectPublicKeyInfoAsn spki; + int read; + ValueSubjectPublicKeyInfoAsn spki; - try - { - read = reader.PeekEncodedValue().Length; - SubjectPublicKeyInfoAsn.Decode(ref reader, manager.Memory, out spki); - } - catch (AsnContentException e) - { - throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); - } - - DecodeSubjectPublicKeyInfo(ref spki, out oid, out parameters, out keyValue); - return read; + try + { + read = reader.PeekEncodedValue().Length; + ValueSubjectPublicKeyInfoAsn.Decode(ref reader, out spki); + } + catch (AsnContentException e) + { + throw new CryptographicException(SR.Cryptography_Der_Invalid_Encoding, e); } + + DecodeSubjectPublicKeyInfo(ref spki, out oid, out parameters, out keyValue); + return read; } - internal static PublicKey DecodeSubjectPublicKeyInfo(ref SubjectPublicKeyInfoAsn spki) + internal static PublicKey DecodeSubjectPublicKeyInfo(ref ValueSubjectPublicKeyInfoAsn spki) { DecodeSubjectPublicKeyInfo( ref spki, @@ -492,18 +488,16 @@ internal static PublicKey DecodeSubjectPublicKeyInfo(ref SubjectPublicKeyInfoAsn } private static void DecodeSubjectPublicKeyInfo( - ref SubjectPublicKeyInfoAsn spki, + ref ValueSubjectPublicKeyInfoAsn spki, out Oid oid, out AsnEncodedData? parameters, out AsnEncodedData keyValue) { oid = new Oid(spki.Algorithm.Algorithm, null); - keyValue = new AsnEncodedData(spki.SubjectPublicKey.Span); - parameters = spki.Algorithm.Parameters switch - { - ReadOnlyMemory algParameters => new AsnEncodedData(algParameters.Span), - _ => null, - }; + keyValue = new AsnEncodedData(spki.SubjectPublicKey); + parameters = spki.Algorithm.HasParameters ? + new AsnEncodedData(spki.Algorithm.Parameters) : + null; } } }