Open vcsjones opened 2 weeks ago
The content and messaging of this should get sign-off from @bartonjs first.
I tweaked the message a little bit, LGTM.
@bartonjs reading https://github.com/dotnet/runtime/issues/91763 it looks like the Authenticode pieces were cut, is the intention for those to keep using X509Certificate2
ctor and suppress the warning?
Here's code from the SDK where we use this and I had to suppress: https://github.com/dotnet/sdk/blob/70479edb89ef1820051e951c4977f5fdb153f8e1/src/Cli/dotnet/Installer/Windows/Security/Signature.cs#L32-L35
Also there's quite a lot of code that uses the approach shown in https://stackoverflow.com/questions/72096812/loading-x509certificate2-from-pem-file-results-in-no-credentials-are-available/72101855#72101855 to export+import a cert to workaround some Windows issue, is that contuing to work with export+X509CertificateLoader.LoadCertificate ?
reading https://github.com/dotnet/runtime/issues/91763 it looks like the Authenticode pieces were cut, is the intention for those to keep using X509Certificate2 ctor and suppress the warning?
More or less. For anyone still using that ctor, but expecting a certain content type, the recommendation is to do something like
if (X509Certificate2.GetCertContentType(input) != X509ContentType.TheOneIExpect)
{
throw new CryptographicException();
}
#pragma warning disable SYSLIB0057
X509Certificate2 cert = new(input);
#pragma warning restore
export+import a cert to workaround some Windows issue, is that contuing to work with export+X509CertificateLoader.LoadCertificate
Yeah, just now it's X509CertificateLoader.LoadPkcs12(cert.Export(X509ContentType.Pkcs12, null))
Ok. It's a bit sad that we have to suppress the warning for the Authenticode case but so be it :) Probably good to mention this in the doc somewhere.
export+import a cert to workaround some Windows issue, is that contuing to work with export+X509CertificateLoader.LoadCertificate
Yeah, just now it's
X509CertificateLoader.LoadPkcs12(cert.Export(X509ContentType.Pkcs12, null))
@bartonjs HI Jeremy, i believe that question you quoted was in reference to PEM files. How do we get an x509Certificate2Collection for a PEM file with multiple certs/keys that has been read in and is now in a byte[]?
Thanks.
@ScotMac If you actually mean PEM when you say PEM, then that's X509Certificate2Collection.ImportFromPem, which is not being marked as obsolete.
If you meant PFX when you said PEM, that's X509CertificateLoader.LoadPkcs12Collection.
Oh, I slightly lied. The Collection ImportFromPem won't import private keys. There's no API for loading multiple certificates and multiple private keys from PEM. Only PFX supports multiple private keys.
@bartonjs Thanks Jeremy.
Yes, it appears that API will only read in public key certs. Is there no .NET API for parsing PEM data that contains at least one private key, and possibly multiple public key certs? Thus providing a way to get the key/certs necessary to estabish an mTLS connection (including the validation of the server cert), without using MCS (cert stores).
And yes, i meant PEM.
But thanks for that p12 load function, since we are currently using x509Certificate2Collection.Import() for p12, which appears to be obsoleted by this notice.
Description
The constructors on
X509Certificate
andX509Certificate2
that accept content as abyte[]
,ReadOnlySpan<byte>
, or astring
file path have been marked obsolete.The
Import
method and all overloads onX509Certificate2Collection
have also been marked obsolete.Version
.NET 9 Preview 7
Previous behavior
Developers could use those APIs without an obsolete warning.
New behavior
Affected APIs will receive an obsolete compilation warning with SYSLIB0057.
Type of breaking change
Reason for change
The affected APIs supported loading certificates in multiple formats. For example,
new X509Certificate2(data)
would load a certificate from abyte[]
called data. This data could be one of any supported format, including X.509, PKCS7, or PKCS12/PFX.While this was easy to use, it created issues where user-supplied data is passed with a different format than intended. This may allow loading PKCS12 where only X.509 content was intended to be loaded, or create interoperability issues from handling the data in different ways.
Recommended action
Developers should use a different API to load certificate content, depending on the intended content type.
A new class called
X509CertificateLoader
can be used to load X.509 or PKCS12 content.X509CertificateLoader.LoadCertificate
andX509CertificateLoader.LoadCertificateFromFile
can be used.X509CertificateLoader.LoadPkcs12
,X509CertificateLoader.LoadPkcs12FromFile
,X509CertificateLoader.LoadPkcs12Collection
, andX509CertificateLoader.LoadPkcs12CollectionFromFile
can be used.SignedCms
from theSystem.Security.Cryptography.Pkcs
package can be used to inspect certificates in PKCS7 content.If you are uncertain about the content type you are loading,
X509Certificate2.GetCertContentType
can be used to determine the content type and call the appropriate API.You may also suppress the obsoletion using
#pragma warning disable SYSLIB0057
and#pragma warning restore SYSLIB0057
around the affected code to continue using the legacy certificate loading APIs.The
Microsoft.Bcl.Cryptography
package suppliesX509CertificateLoader
for .NET Framework and .NET Standard.Feature area
Cryptography
Affected APIs
Affected Doc IDs:
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.Byte[])
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.ReadOnlySpan{System.Byte})
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.String)
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.Byte[],System.Security.SecureString)
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.Byte[],System.String)
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.String,System.Security.SecureString)
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.String,System.String)
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.Byte[],System.Security.SecureString,System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.Byte[],System.String,System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.ReadOnlySpan{System.Byte},System.ReadOnlySpan{System.Char},System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.String,System.ReadOnlySpan{System.Char},System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.String,System.Security.SecureString,System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate2.#ctor(System.String,System.String,System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate.#ctor(System.Byte[])
M:System.Security.Cryptography.X509Certificates.X509Certificate.#ctor(System.String)
M:System.Security.Cryptography.X509Certificates.X509Certificate.#ctor(System.Byte[],System.Security.SecureString)
M:System.Security.Cryptography.X509Certificates.X509Certificate.#ctor(System.Byte[],System.String)
M:System.Security.Cryptography.X509Certificates.X509Certificate.#ctor(System.String,System.String,System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate.#ctor(System.String,System.Security.SecureString)
M:System.Security.Cryptography.X509Certificates.X509Certificate.#ctor(System.String,System.String)
M:System.Security.Cryptography.X509Certificates.X509Certificate.#ctor(System.Byte[],System.Security.SecureString,System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate.#ctor(System.Byte[],System.String,System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate.#ctor(System.String,System.Security.SecureString,System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate.#ctor(System.String,System.String,System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate2Collection.Import(System.Byte[])
M:System.Security.Cryptography.X509Certificates.X509Certificate2Collection.Import(System.ReadOnlySpan{System.Byte})
M:System.Security.Cryptography.X509Certificates.X509Certificate2Collection.Import(System.ReadOnlySpan{System.Byte})
M:System.Security.Cryptography.X509Certificates.X509Certificate2Collection.Import(System.Byte[],System.String,System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate2Collection.Import(System.ReadOnlySpan{System.Byte},System.ReadOnlySpan{System.Char},System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate2Collection.Import(System.ReadOnlySpan{System.Byte},System.String,System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate2Collection.Import(System.String,System.ReadOnlySpan{System.Char},System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
M:System.Security.Cryptography.X509Certificates.X509Certificate2Collection.Import(System.String,System.String,System.Security.Cryptography.X509Certificates.X509KeyStorageFlags)
"M:System.Security.Cryptography.X509Certificates.X509Certificate.CreateFromSignedFile(System.String)