I have a certificate that I'm trying to load in .NET. I noticed that in .NET 9 the X509Certificate2
constructor has been deprecated in favor of X509CertificateLoader
. So to prepare for that (still in .NET 7) I pulled in the Microsoft.Bcl.Cryptography
package and tried using that class. However, X509CertificateLoader
fails unless I provide a very adventurous-sounding configuration value:
// This works
cert = X509CertificateLoader.LoadPkcs12FromFile(certPath, clientId, loaderLimits: Pkcs12LoaderLimits.DangerousNoLimits);
// This throws CryptographicException
cert = X509CertificateLoader.LoadPkcs12FromFile(certPath, clientId);
Stacktrace:
at System.Security.Cryptography.NetStandardShims.TryGetHashAndReset(IncrementalHash hash, Span`1 destination, Int32& bytesWritten)
at System.Security.Cryptography.Asn1.Pkcs12.PfxAsn.VerifyMac(ReadOnlySpan`1 macPassword, ReadOnlySpan`1 authSafeContents)
at System.Security.Cryptography.X509Certificates.X509CertificateLoader.ReadCertsAndKeys(BagState& bagState, ReadOnlyMemory`1 data, ReadOnlySpan`1& password, Pkcs12LoaderLimits loaderLimits)
at System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadPkcs12(ReadOnlyMemory`1 data, ReadOnlySpan`1 password, X509KeyStorageFlags keyStorageFlags, Pkcs12LoaderLimits loaderLimits)
at System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadFromFile[T](String path, ReadOnlySpan`1 password, X509KeyStorageFlags keyStorageFlags, Pkcs12LoaderLimits loaderLimits, LoadFromFileFunc`1 loader)
at System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadPkcs12FromFile(String path, ReadOnlySpan`1 password, X509KeyStorageFlags keyStorageFlags, Pkcs12LoaderLimits loaderLimits)
at System.Security.Cryptography.X509Certificates.X509CertificateLoader.LoadPkcs12FromFile(String path, String password, X509KeyStorageFlags keyStorageFlags, Pkcs12LoaderLimits loaderLimits)
Tangentially, I cannot seem to figure out how this exception happens, as this code should force hashAlgorithm
to be one of these values, thereby avoiding the line where this exception is thrown. But anyway, as documented, this Pkcs12LoaderLimits.DangerousNoLimits
setting causes the loader to follow a different code path, which avoids the problem. Simply changing the loader limits to have similar options to Pkcs12LoaderLimits.DangerousNoLimits
does not solve the problem.
What "filtering" am I skipping which is potentially dangerous here? What am I risking by using this option? Is there likely something about the certificate file itself that makes it incompatible with the default settings? Something I could change so that I don't have to use the "dangerous" lack of filtering?
This turned out to be a bug in the .NET Standard 2.0 implementation of Microsoft.Bcl.Cryptography. The reason you hit this is because you are using .NET 7, which is out of support, and the package does not provide targets for out of support framework versions, so you ended up getting the .NET Standard 2.0 build.
The build for .NET Standard 2.0 has been fixed. In the mean time, you have a few options for how to proceed.
The best option would be to get on a supported version of .NET. If you at least move to .NET 8, then Microsoft.Bcl.Cryptography
will no longer fall back to giving you the netstandard2.0 build. If you target .NET 9, then you don't need the package at all because X509CertificateLoader
is included in the box.
Suppress the SYSLIB0057 obsoletion with a #pragma
and keep using the constructors until you can get on a supported framework version. Using DangerousNoLimits
might work if you are on Windows. I am not sure it will work as a workaround on non-Windows platforms.
At some point, a fixerd version of Microsoft.Bcl.Cryptography will get released, but that could be several months of waiting at worst.