Skip to content

Private key loaded with X509Certificate2.CreateFromPem is not usable for ECDH on Windows #115232

@PetSerAl

Description

@PetSerAl

Description

When certificate is both ECDSA and ECDH in terms of:

private static bool IsECDsa(X509Certificate2 certificate)
{
using (ECDsa? ecdsa = certificate.GetECDsaPublicKey())
{
return ecdsa is not null;
}
}
private static bool IsECDiffieHellman(X509Certificate2 certificate)
{
using (ECDiffieHellman? ecdh = certificate.GetECDiffieHellmanPublicKey())
{
return ecdh is not null;
}
}

Then private key loaded with X509Certificate2.CreateFromPem is not usable for ECDH on Windows.

Reproduction Steps

using System;
using System.Security.Cryptography.X509Certificates;

var pem = """
-----BEGIN CERTIFICATE-----
MIIBFDCBu6ADAgECAgkAvDLCg4b2/VwwCgYIKoZIzj0EAwIwDzENMAsGA1UEAwwE
VGVzdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowDzENMAsGA1UE
AwwEVGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFxeYPoaE/s7F4GQqTE/
eGfWmhQIgxkVNYKZk7z4mfAylUmbZ6Axbt04eatl9RMOFjHFH20hOg51/300otK6
x1IwCgYIKoZIzj0EAwIDSAAwRQIhAJ8PLaxaX/mtYSaQ+Ar/xkesnkc69R6B59+Z
4GGcpS7FAiBe3mEFY/bmB3qJYSYRMGjytQ/98v5LYSZHAaDx87uZMQ==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgT0q0yhmyYKLP9yPB
SKubBJFheOfrvBquIkhIm+br38uhRANCAARcXmD6GhP7OxeBkKkxP3hn1poUCIMZ
FTWCmZO8+JnwMpVJm2egMW7dOHmrZfUTDhYxxR9tIToOdf99NKLSusdS
-----END PRIVATE KEY-----
""";
var certificate = X509Certificate2.CreateFromPem(pem, pem);
Console.WriteLine(certificate.GetECDsaPrivateKey() is null);
Console.WriteLine(certificate.GetECDiffieHellmanPrivateKey() is null);

Expected behavior

False
False

Actual behavior

False
True

Regression?

No response

Known Workarounds

Explicitly load private key with ECDiffieHellman:

using System;
using System.Security.Cryptography;
using System.Security.Cryptography.X509Certificates;

var pem = """
-----BEGIN CERTIFICATE-----
MIIBFDCBu6ADAgECAgkAvDLCg4b2/VwwCgYIKoZIzj0EAwIwDzENMAsGA1UEAwwE
VGVzdDAgFw0wMDAxMDEwMDAwMDBaGA8yMTAwMDEwMTAwMDAwMFowDzENMAsGA1UE
AwwEVGVzdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABFxeYPoaE/s7F4GQqTE/
eGfWmhQIgxkVNYKZk7z4mfAylUmbZ6Axbt04eatl9RMOFjHFH20hOg51/300otK6
x1IwCgYIKoZIzj0EAwIDSAAwRQIhAJ8PLaxaX/mtYSaQ+Ar/xkesnkc69R6B59+Z
4GGcpS7FAiBe3mEFY/bmB3qJYSYRMGjytQ/98v5LYSZHAaDx87uZMQ==
-----END CERTIFICATE-----
-----BEGIN PRIVATE KEY-----
MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgT0q0yhmyYKLP9yPB
SKubBJFheOfrvBquIkhIm+br38uhRANCAARcXmD6GhP7OxeBkKkxP3hn1poUCIMZ
FTWCmZO8+JnwMpVJm2egMW7dOHmrZfUTDhYxxR9tIToOdf99NKLSusdS
-----END PRIVATE KEY-----
""";
var certificate = X509Certificate2.CreateFromPem(pem);
var key = ECDiffieHellman.Create();
key.ImportFromPem(pem);
certificate = certificate.CopyWithPrivateKey(key);
Console.WriteLine(certificate.GetECDsaPrivateKey() is null);
Console.WriteLine(certificate.GetECDiffieHellmanPrivateKey() is null);

Configuration

.NET SDK:
 Version:           9.0.203
 Commit:            dc7acfa194
 Workload version:  9.0.200-manifests.9df47798
 MSBuild version:   17.13.20+a4ef1e90f

Runtime Environment:
 OS Name:     Windows
 OS Version:  10.0.26100
 OS Platform: Windows
 RID:         win-x64
 Base Path:   C:\Program Files\dotnet\sdk\9.0.203\

Host:
  Version:      9.0.4
  Architecture: x64
  Commit:       f57e6dc747

.NET SDKs installed:
  9.0.203 [C:\Program Files\dotnet\sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 9.0.4 [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 9.0.4 [C:\Program Files\dotnet\shared\Microsoft.NETCore.App]
  Microsoft.WindowsDesktop.App 9.0.4 [C:\Program Files\dotnet\shared\Microsoft.WindowsDesktop.App]

As far as I understand, issue is specific for Windows.

Other information

On Windows CngKey for EC key marked with AlgorithmGroup ECDSA or ECDH. ECDH keys can be used in both algorithms, while ECDSA keys can be used only with ECDSA. As such when key should be usable in both algorithms, then it should be loaded as ECDH. Following code fragment load them as ECDSA:

Oids.EcPublicKey when IsECDsa(certificate) =>
ExtractKeyFromPem<ECDsa>(
keyPem,
s_EcPublicKeyPrivateKeyLabels,
static keyPem => CreateAndImport(keyPem, ECDsa.Create),
certificate.CopyWithPrivateKey),
Oids.EcPublicKey when IsECDiffieHellman(certificate) =>
ExtractKeyFromPem<ECDiffieHellman>(
keyPem,
s_EcPublicKeyPrivateKeyLabels,
static keyPem => CreateAndImport(keyPem, ECDiffieHellman.Create),
certificate.CopyWithPrivateKey),

Switch cases Oids.EcPublicKey when IsECDsa(certificate) and Oids.EcPublicKey when IsECDiffieHellman(certificate) should be reordered to load them as ECDH.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions