I believe this is a bug. The following snippet asserts "true/true" on Windows and "false/false" on Linux.
```c#
var ecDsa = ECDsa.Create(ECCurve.NamedCurves.nistP521);
var x509 = new CertificateRequest(
"CN=foo", ecDsa, HashAlgorithmName.SHA512).CreateSelfSigned(
DateTime.UtcNow.Add(TimeSpan.FromMinutes(-1)),
DateTime.UtcNow.Add(TimeSpan.FromDays(365)));
var pfxBytes = x509.Export(X509ContentType.Pkcs12, "password");
var cert2 = new X509Certificate2(pfxBytes, "password");
var privKey = cert2.GetECDsaPrivateKey();
Console.WriteLine("cert2.HasPrivateKey: {0}", cert2.HasPrivateKey);
Console.WriteLine("privKey != null: {0}", privKey != null);
```
cc: @bartonjs
Hm. I can reproduce it, but I don't yet understand it.
Using the Pkcs12Info class in master, I see that the PFX blob does, in fact, contain the key and the certificate. But PKCS12_parse just didn't say they were matched. Pretty weird since PKCS12_create is what made it.
New contents Confidentiality=Password
New bag: 1.2.840.113549.1.12.10.1.3
New attr (1.2.840.113549.1.9.21): 04148E3102431BAAB84703D0DFDB5941BD88A205EDFD
New contents Confidentiality=None
New bag: 1.2.840.113549.1.12.10.1.2
New attr (1.2.840.113549.1.9.21): 04148E3102431BAAB84703D0DFDB5941BD88A205EDFD
So that was a shrouded key bag with a key identifier and a certificate with the same key identifier.
It's possible, with the new Pkcs12Info class and ImportPkcs8PrivateKey/ImportEncryptedPkcs8PrivateKey to overcome this manually.
I was hoping to replace our PFX code with a manual importer for the 3.0 release, but we've just run out of time. Hopefully this was just a bug in OpenSSL and they've fixed it (particularly since we've gained support for OpenSSL 1.1.x this release (and backported to 2.1/2.2 after this issue was opened)).
Some good news: This does look to be an OpenSSL bug that is fixed in the 1.1 line. On current builds of .NET Core 2.x OpenSSL 1.1.x can be preferentially loaded via setting the environment variable CLR_OPENSSL_VERSION_OVERRIDE to 1.1 (assuming you have libssl.so.1.1/libcrypto.so.1.1 in your library path)
@bartonjs said: I was hoping to replace our PFX code with a manual importer for the 3.0 release
This might not be the appropriate venue, but I'd like to hear more about this. I'm working on porting an old .NET 2.0 web service that utilized certificates in the windows store to dotnet core on Linux and had to write my own pfx importer, I was surprised that there was both no official functionality nor anything community based that I could find.
@mletterle In .NET Core 3.0 there's a type, Pkcs12Info that you can use to go through the contents of a PFX. (And Pkcs12Builder to make new ones). They're both in the System.Security.Cryptography.Pkcs package.
Most helpful comment
Some good news: This does look to be an OpenSSL bug that is fixed in the 1.1 line. On current builds of .NET Core 2.x OpenSSL 1.1.x can be preferentially loaded via setting the environment variable
CLR_OPENSSL_VERSION_OVERRIDEto1.1(assuming you have libssl.so.1.1/libcrypto.so.1.1 in your library path)