diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/StorePal.Android.AndroidKeyStore.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/StorePal.Android.AndroidKeyStore.cs index 59c70f4ae78c46..916da956c2307b 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/StorePal.Android.AndroidKeyStore.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/StorePal.Android.AndroidKeyStore.cs @@ -118,7 +118,7 @@ public void CloneTo(X509Certificate2Collection collection) private static string GetCertificateHashString(ICertificatePal certPal) { - return X509Certificate.GetCertHashString(HashAlgorithmName.SHA256, certPal); + return X509Certificate.GetCertHashString(HashAlgorithmName.SHA256, certPal.RawData); } private struct EnumCertificatesContext diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate.cs index e186cdd15823fa..d010f6f21c96bc 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate.cs @@ -25,6 +25,7 @@ public class X509Certificate : IDisposable, IDeserializationCallback, ISerializa private volatile string? _lazyKeyAlgorithm; private volatile byte[]? _lazyKeyAlgorithmParameters; private volatile byte[]? _lazyPublicKey; + private volatile byte[]? _lazyRawData; private DateTime _lazyNotBefore = DateTime.MinValue; private DateTime _lazyNotAfter = DateTime.MinValue; @@ -37,6 +38,7 @@ public virtual void Reset() _lazyKeyAlgorithm = null; _lazyKeyAlgorithmParameters = null; _lazyPublicKey = null; + _lazyRawData = null; _lazyNotBefore = DateTime.MinValue; _lazyNotAfter = DateTime.MinValue; @@ -242,6 +244,15 @@ void IDeserializationCallback.OnDeserialization(object? sender) throw new PlatformNotSupportedException(); } + private protected ReadOnlyMemory PalRawDataMemory + { + get + { + ThrowIfInvalid(); + return _lazyRawData ??= Pal.RawData; + } + } + public IntPtr Handle => Pal is null ? IntPtr.Zero : Pal.Handle; public string Issuer @@ -343,12 +354,7 @@ public virtual byte[] GetCertHash() public virtual byte[] GetCertHash(HashAlgorithmName hashAlgorithm) { ThrowIfInvalid(); - return GetCertHash(hashAlgorithm, Pal); - } - - private static byte[] GetCertHash(HashAlgorithmName hashAlgorithm, ICertificatePalCore certPal) - { - return CryptographicOperations.HashData(hashAlgorithm, certPal.RawData); + return CryptographicOperations.HashData(hashAlgorithm, PalRawDataMemory.Span); } public virtual bool TryGetCertHash( @@ -358,7 +364,7 @@ public virtual bool TryGetCertHash( { ThrowIfInvalid(); - return CryptographicOperations.TryHashData(hashAlgorithm, Pal.RawData, destination, out bytesWritten); + return CryptographicOperations.TryHashData(hashAlgorithm, PalRawDataMemory.Span, destination, out bytesWritten); } public virtual string GetCertHashString() @@ -370,13 +376,15 @@ public virtual string GetCertHashString() public virtual string GetCertHashString(HashAlgorithmName hashAlgorithm) { ThrowIfInvalid(); - - return GetCertHashString(hashAlgorithm, Pal); + return GetCertHashString(hashAlgorithm, PalRawDataMemory.Span); } - internal static string GetCertHashString(HashAlgorithmName hashAlgorithm, ICertificatePalCore certPal) + internal static string GetCertHashString(HashAlgorithmName hashAlgorithm, ReadOnlySpan rawData) { - return GetCertHash(hashAlgorithm, certPal).ToHexStringUpper(); + Span buffer = stackalloc byte[64]; // Largest supported hash size is 512 bits + + int written = CryptographicOperations.HashData(hashAlgorithm, rawData, buffer); + return Convert.ToHexString(buffer.Slice(0, written)); } // Only use for internal purposes when the returned byte[] will not be mutated @@ -409,7 +417,7 @@ public virtual byte[] GetRawCertData() { ThrowIfInvalid(); - return Pal.RawData.CloneByteArray(); + return PalRawDataMemory.ToArray(); } public override int GetHashCode() diff --git a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs index eb1a21fb98f1a0..d6a9ba6ef0d5a5 100644 --- a/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs +++ b/src/libraries/System.Security.Cryptography/src/System/Security/Cryptography/X509Certificates/X509Certificate2.cs @@ -16,7 +16,6 @@ namespace System.Security.Cryptography.X509Certificates { public class X509Certificate2 : X509Certificate { - private volatile byte[]? _lazyRawData; private volatile Oid? _lazySignatureAlgorithm; private volatile int _lazyVersion; private volatile X500DistinguishedName? _lazySubjectName; @@ -30,7 +29,6 @@ public class X509Certificate2 : X509Certificate public override void Reset() { - _lazyRawData = null; _lazySignatureAlgorithm = null; _lazyVersion = 0; _lazySubjectName = null; @@ -327,15 +325,7 @@ public PublicKey PublicKey /// Unlike , this does not create a fresh copy of the data /// every time. /// - public ReadOnlyMemory RawDataMemory - { - get - { - ThrowIfInvalid(); - - return _lazyRawData ??= Pal.RawData; - } - } + public ReadOnlyMemory RawDataMemory => PalRawDataMemory; public string SerialNumber => GetSerialNumberString();