Runtime: X509Certificate2 fails to import ECDSA private key from Pkcs12 on Linux

Created on 13 Aug 2018  路  5Comments  路  Source: dotnet/runtime

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

area-System.Security bug os-linux

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_OVERRIDE to 1.1 (assuming you have libssl.so.1.1/libcrypto.so.1.1 in your library path)

All 5 comments

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.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

aggieben picture aggieben  路  3Comments

omariom picture omariom  路  3Comments

yahorsi picture yahorsi  路  3Comments

iCodeWebApps picture iCodeWebApps  路  3Comments

matty-hall picture matty-hall  路  3Comments