C# 将证书和密钥 (PFX) 导入 CNG/KSP
C# import certificate and key (PFX) into CNG/KSP
我正在尝试将 certificate/key (PFX) 导入到 Windows 证书存储区,使用 KSP 来存储密钥。这背后的想法是能够使用自定义 KSP,即使现在我只是使用默认 KSP。
使用 CNG 将密钥存储到 KSP 中是 "easy" 部分,这里是对我有用的代码:
X509Certificate2 cert = new X509Certificate2(@"c:\temp\test.pfx", "test123", X509KeyStorageFlags.Exportable);
RSACng rsaCNG = new RSACng();
rsaCNG.FromXmlString(cert.GetRSAPrivateKey().ToXmlString(true));
var keyData = rsaCNG.Key.Export(CngKeyBlobFormat.GenericPrivateBlob);
var keyParams = new CngKeyCreationParameters
{
ExportPolicy = CngExportPolicies.None,
KeyCreationOptions = CngKeyCreationOptions.MachineKey,
Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider
};
keyParams.Parameters.Add(new CngProperty(CngKeyBlobFormat.GenericPrivateBlob.Format, keyData, CngPropertyOptions.None));
var key = CngKey.Create(CngAlgorithm.Rsa, "testKey", keyParams);
但是,我无法将此密钥与证书相关联,以便将证书正确存储到 Windows 存储中。以下代码:
rsaCNG = new RSACng(key);
X509Certificate2 certOnly = new X509Certificate2(cert.Export(X509ContentType.Cert));
certOnly.PrivateKey = rsaCNG;
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(certOnly);
store.Close();
失败,异常:Only asymmetric keys that implement ICspAsymmetricAlgorithm are supported.
在行 certOnly.PrivateKey = rsaCNG
。
有人知道怎么做吗?我正在使用 .NET Framework 4.6.2,并希望尽可能避免使用 P/Invoke。我可以升级到 .NET Framework 4。7.X 如有必要,尽管代码在 4.7.2 中引发了相同的错误。
使用 4.7.2 的 CopyWithPrivateKey
扩展方法,它可以理解 CAPI 和 CNG 密钥。
// certWithKey understands it has a persisted key reference if rsaCNG's key is
// a named key, so adding it to the store and reading it back will work.
X509Certificate2 certWithKey = certOnly.CopyWithPrivateKey(rsaCNG);
...
store.Add(certWithKey);
...
虽然 bartonjs 的答案适用于 Microsoft 软件密钥存储提供程序,但由于 a bug in the KSP or .NET PKI Guy 已经指出(导入的密钥具有IsMachineKey false).
有一种解决方法适用于平台密钥存储提供程序,甚至适用于机器密钥:https://github.com/glueckkanja-pki/TPMImport
我正在尝试将 certificate/key (PFX) 导入到 Windows 证书存储区,使用 KSP 来存储密钥。这背后的想法是能够使用自定义 KSP,即使现在我只是使用默认 KSP。
使用 CNG 将密钥存储到 KSP 中是 "easy" 部分,这里是对我有用的代码:
X509Certificate2 cert = new X509Certificate2(@"c:\temp\test.pfx", "test123", X509KeyStorageFlags.Exportable);
RSACng rsaCNG = new RSACng();
rsaCNG.FromXmlString(cert.GetRSAPrivateKey().ToXmlString(true));
var keyData = rsaCNG.Key.Export(CngKeyBlobFormat.GenericPrivateBlob);
var keyParams = new CngKeyCreationParameters
{
ExportPolicy = CngExportPolicies.None,
KeyCreationOptions = CngKeyCreationOptions.MachineKey,
Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider
};
keyParams.Parameters.Add(new CngProperty(CngKeyBlobFormat.GenericPrivateBlob.Format, keyData, CngPropertyOptions.None));
var key = CngKey.Create(CngAlgorithm.Rsa, "testKey", keyParams);
但是,我无法将此密钥与证书相关联,以便将证书正确存储到 Windows 存储中。以下代码:
rsaCNG = new RSACng(key);
X509Certificate2 certOnly = new X509Certificate2(cert.Export(X509ContentType.Cert));
certOnly.PrivateKey = rsaCNG;
X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
store.Open(OpenFlags.ReadWrite);
store.Add(certOnly);
store.Close();
失败,异常:Only asymmetric keys that implement ICspAsymmetricAlgorithm are supported.
在行 certOnly.PrivateKey = rsaCNG
。
有人知道怎么做吗?我正在使用 .NET Framework 4.6.2,并希望尽可能避免使用 P/Invoke。我可以升级到 .NET Framework 4。7.X 如有必要,尽管代码在 4.7.2 中引发了相同的错误。
使用 4.7.2 的 CopyWithPrivateKey
扩展方法,它可以理解 CAPI 和 CNG 密钥。
// certWithKey understands it has a persisted key reference if rsaCNG's key is
// a named key, so adding it to the store and reading it back will work.
X509Certificate2 certWithKey = certOnly.CopyWithPrivateKey(rsaCNG);
...
store.Add(certWithKey);
...
虽然 bartonjs 的答案适用于 Microsoft 软件密钥存储提供程序,但由于 a bug in the KSP or .NET PKI Guy 已经指出(导入的密钥具有IsMachineKey false).
有一种解决方法适用于平台密钥存储提供程序,甚至适用于机器密钥:https://github.com/glueckkanja-pki/TPMImport