Description
Background and motivation
Problem
When importing a PFX file using X509Store.Import()
or X509Certificate2.Import()
on Linux, the private key is extracted and stored in clear text under:
📂 ~/.dotnet/corefx/cryptography/x509stores/
This is different from Windows, where private keys can be securely stored in KeyStore and protected by mechanisms like DPAPI.
The current behavior on Linux does not allow for encrypted storage of private keys, which poses a security risk for users.
Repro Steps
var cert = new X509Certificate2("mycert.pfx", "password",
X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.UserKeySet);
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Add(cert);
store.Close();
🔹 This process stores the private key in clear text within ~/.dotnet/corefx/cryptography/x509stores/
.
Expected Behavior
- The
X509Store.Import()
functionality should allow for encrypted storage of private keys. - Alternatively, there should be a flag or mechanism in
X509KeyStorageFlags
that enforces secure storage of the private key during the import process. - The
X509Store
API should handle private key storage in a more secure way, similar to how it's handled on Windows or macOS (e.g., using Keychain on macOS or TPM on Windows).
Actual Behavior
- Private keys are stored in clear text on Linux systems.
- There is no mechanism to encrypt the private key during the import process, leaving sensitive information exposed.
Proposed Solution
- Provide a flag like
X509KeyStorageFlags.SecureImport
that encrypts private keys automatically during the import process. - Integrate with OS-native key management systems such as libsecret, GPG, or OpenSSL to securely store private keys.
- Allow .NET users to load and store encrypted PFX files without extracting keys to unprotected disk storage.
- Ensure the behavior is consistent across platforms (Linux, macOS, Windows) for private key storage.
Environment
- .NET Version: 8.0 (and prior)
- OS: Linux (Ubuntu, Debian, RHEL, etc.)
- Reproducible: ✅ Yes, always
Security Risk
This exposes private keys to unauthorized access unless users manually encrypt or use external security mechanisms, which can be cumbersome and error-prone.
Additional Context
- Windows uses DPAPI for private key protection.
- macOS uses the Keychain for secure private key storage.
- Linux lacks native, consistent private key protection mechanisms for .NET applications, and users must resort to custom workarounds like encrypting the PFX file manually before import.
API Proposal
public enum X509KeyProtectionMode
{
None, // Default (current behavior, unprotected storage)
UserSecret, // Encrypts private keys using a user-provided secret
SecureStore // Uses OS-native secure storage (DPAPI, Keychain, libsecret, etc.)
}
public sealed class X509Store
{
// New overload of the Add method with key protection mode
public void Add(X509Certificate2 certificate, X509KeyProtectionMode protectionMode, string? userSecret = null)
{
if (protectionMode == X509KeyProtectionMode.UserSecret && string.IsNullOrEmpty(userSecret))
{
throw new ArgumentException("UserSecret cannot be null when using UserSecret mode.");
}
// Logic to securely store the private key using the chosen protection mode
}
// Existing method (for backward compatibility)
public void Add(X509Certificate2 certificate) { /* Default behavior */ }
}
API Usage
- Use UserSecret for Encryption
var cert = new X509Certificate2("mycert.pfx", "password",
X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.UserKeySet);
var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Add(cert, X509KeyProtectionMode.UserSecret, "MySecureUserSecret");
store.Close();
- Use OS Secure Storage
store.Add(cert, X509KeyProtectionMode.SecureStore);
- Default (No Protection, Current Behavior)
store.Add(cert, X509KeyProtectionMode.SecureStore);
Alternative Designs
No response
Risks
This exposes private keys to unauthorized access unless users manually encrypt or use external security mechanisms, which can be cumbersome and error-prone.