It is possible to specify X509KeyStorageFlags in X509Certificate2 constructor what would look like this:
var cert = new X509Certificate2(bytes, password, X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
But in my case I use CertificateRequest to create self signed certificate so I do not have a certificate constructor:
var rsaKeyPair = RSA.Create();
var request = new CertificateRequest(
$"cn = {Environment.MachineName}",
rsaKeyPair,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs);
request.CertificateExtensions.Add(
new X509KeyUsageExtension(X509KeyUsageFlags.KeyEncipherment |
X509KeyUsageFlags.DigitalSignature, true));
var certificate = request.CreateSelfSigned(new DateTimeOffset(DateTime.UtcNow),
new DateTimeOffset(DateTime.UtcNow.AddYears(2)));
Is there a way to add KeyStorageFags to request.CertificateExtension or something like that?
How to provide X509KeyStorageFlags to CertificateRequest
CertificateRequest doesn't understand anything about key storage. All it does is build the certificate, then call cert.CopyWithPrivateKey(privateKey)
.
Moving the target:
How to provide X509KeyStorageFlags to CopyWithPrivateKey
CopyWithPrivateKey copies the key in its current state. Ephemeral keys stay ephemeral. Persisted keys stay persisted.
Moving the target:
How to provide X509KeyStorageFlags to RSA.Create()
RSA.Create() always creates ephemeral keys, it doesn't understand key storage at all. You'd have to use a specific RSA implementation that understands persistence -- but that then locks you into Windows (of course, you could have your calling code vary on OS).
RSA rsaKeyPair = BuildMachinePersistedKeyPair(2048);
...
private static RSA BuildMachinePersistedKeyPair(int keySize)
{
CngKeyCreationParameters creationParameters = new CngKeyCreationParameters()
{
ExportPolicy = CngExportPolicies.Exportable,
Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider,
KeyCreationOptions =
CngKeyCreationOptions.OverwriteExistingKey |
CngKeyCreationOptions.MachineKey,
};
CngProperty keySizeProperty = new CngProperty(
KeyPropertyName.Length,
BitConverter.GetBytes(keySize),
CngPropertyOptions.None);
creationParameters.Parameters.Add(keySizeProperty);
using (CngKey cngKey = CngKey.Create(CngAlgorithm.Rsa, Guid.NewGuid().ToString(), creationParameters))
{
return new RSACng(cngKey);
}
}
Is there an easier way?
Sure, just export/import the ephemeral one.
X509Certificate2 certificate;
using (X509Certificate2 ephemeral = request.CreateSelfSigned(...))
{
certificate = new X509Certificate2(
ephemeral.Export(X509ContentType.Pkcs12),
string.Empty,
X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.Exportable);
}