dotnet / dotnet/runtime

X509Certificate2.CopyWithPrivateKey breaks with PKCS.11 OpenSSL Providers and ECDSA

Open
#133,171 10 comments 0 reactions 1 assignee Claimed by @vcsjones View on GitHub
area-System.Security
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Description

On Linux, we use PKCS.11 through an OpenSSL Engine to interact with an on-device HSM. In trying to switch to OpenSSL providers, it looks like this works with the deprecated OpenSSL engine but not a Provider. RSA works with Providers.

### Reproduction Steps

https://github.com/wjohnstonsolventum/dotnet-openssl-ecdsa-bug/blob/main/HsmPoc/Program.cs

You can clone that codebase and run `./start.sh engine` and it'll work, and `./start.sh provider` and it'll fail. Based on https://github.com/dotnet/runtime/issues/109243#issuecomment-2438890361 it seems like it should work. If you switch this to RSA, it works fine with both engines and providers.

### Expected behavior

This should work with providers too.

Engine output from reproduction steps:
```
Engine "pkcs11" set.
Workaround for OpenSSL 3.0.13 30 Jan 2024 enabled
Workaround for OpenSSL 3.0.13 30 Jan 2024 enabled
Subject: CN=hsm-poc
Load mode: engine
Has private key: True
Signature valid: True
```

### Actual behavior

Providers:
```
Engine "pkcs11" set.
Workaround for OpenSSL 3.0.13 30 Jan 2024 enabled
Unhandled exception. System.Security.Cryptography.CryptographicException: Error occurred during a cryptographic operation.
at Interop.Crypto.EvpPKeyGetEcKeyParameters(SafeEvpPKeyHandle key, Boolean includePrivate)
at System.Security.Cryptography.ECOpenSsl.ExportNamedCurveParametersFromEvpPKeyUsingParams(SafeEvpPKeyHandle pkey, String curveName, Boolean includePrivateParameters)
at System.Security.Cryptography.ECOpenSsl.ExportParameters(SafeEvpPKeyHandle pkey, Boolean includePrivateParameters)
at System.Security.Cryptography.X509Certificates.ECDsaCertificateExtensions.CopyWithPrivateKey(X509Certificate2 certificate, ECDsa privateKey)
at Program.$(String[] args) in /src/HsmPoc/Program.cs:line 29
```

### Regression?

This worked with OpenSSL Engines and works with OpenSSL Providers with RSA. I don't think OpenSSL Providers with ECDSA has ever worked.

### Known Workarounds

Use engines or use RSA.

### Configuration

```bash
$ dotnet --version
10.0.301
```

I've seen this on AMD64 in Linux Docker on macOS via Rosetta (see reproduction PoC), and in ARM64 on an embedded Linux device.

This only applies to Linux because of OpenSSL. It seems to be architecture independent within that.

### Other information

_No response_

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.