【发布时间】:2020-03-12 14:57:53
【问题描述】:
我已生成 CSR,并已对其进行签名。我仍然拥有用于创建 CSR 的私钥,并且我想将该证书与该私钥一起存储在 Windows CertStores 中。
我的成功标准是:
当我在 CertStore 中查看证书时,它被标记为具有私钥。具体来说,它在证书图标的左上角有一个小“密钥”子图标,如果你打开证书,它会在 ValidDates 信息下显示“你有一个与此证书相对应的私钥”。
我们最初认为.CopyWithPrivateKey(RSA key) 会为我们做到这一点,但它似乎并不能单独工作。我们还需要设置一些 keyStorage 标志,但我们只能通过 .Export() 将证书写入 byte[] 数组,然后使用另一个构造函数调用“导入”它。
我尝试了很多变体,这是唯一有效的事件序列:
public void InstallCertOnNonUiThread(byte[] certificateDataFromCsrResponse, RSA privateKeyUsedToGenerateCsr)
{
var keyStorageFlags = X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet;
var originalCert = new X509Certificate2(certificateDataFromCsrResponse);
var exportOfOriginalCert = originalCert.Export(X509ContentType.Pkcs12);
var withFlagsCert = new X509Certificate2(certificateDataFromCsrResponse, (SecureString)null, keyStorageFlags);
var exportOfWithFlagsCert = withFlagsCert.Export(X509ContentType.Pkcs12);
var copiedWithPKCert = originalCert.CopyWithPrivateKey(privateKeyUsedToGenerateCsr);
var exportOfCopiedWithPkCert = copiedWithPKCert.Export(X509ContentType.Pkcs12);
var withFlagsReimportOfOriginal = new X509Certificate2(exportOfOriginalCert, (SecureString)null, keyStorageFlags);
var withFlagsReimportOfWithFlags = new X509Certificate2(exportOfWithFlagsCert, (SecureString)null, keyStorageFlags);
var withFlagsReimportOfCopiedWithPK = new X509Certificate2(exportOfCopiedWithPkCert, (SecureString)null, keyStorageFlags);
InstallCertInStore(StoreLocation.LocalMachine, originalCert); // Doesn't work; no key in Store UI.
InstallCertInStore(StoreLocation.LocalMachine, withFlagsCert); // Doesn't work; no key in Store UI.
InstallCertInStore(StoreLocation.LocalMachine, copiedWithPKCert); // Doesn't work; no key in Store UI.
InstallCertInStore(StoreLocation.LocalMachine, withFlagsReimportOfOriginal); // Doesn't work; no key in Store UI.
InstallCertInStore(StoreLocation.LocalMachine, withFlagsReimportOfWithFlags); // Doesn't work; no key in Store UI.
InstallCertInStore(StoreLocation.LocalMachine, withFlagsReimportOfCopiedWithPK);// This one works. Cert has key icon, and text "You have a private key that corresponds to this certificate"
}
private static void InstallCertInStore(StoreLocation location, X509Certificate2 newCert)
{
using (var store = new X509Store(StoreName.My, location))
{
store.Open(OpenFlags.ReadWrite);
store.Add(newCert);
}
}
所以我的最终代码将如下所示:
public Task<bool> InstallCertOnNonUiThread(byte[] certificateDataFromCsrResponse, RSA privateKeyUsedToGenerateCsr, string orgId)
{
var keyStorageFlags = X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet | X509KeyStorageFlags.MachineKeySet;
var originalCert = new X509Certificate2(certificateDataFromCsrResponse);
var copiedWithPKCert = originalCert.CopyWithPrivateKey(privateKeyUsedToGenerateCsr);
var exportOfCopiedWithPkCert = copiedWithPKCert.Export(X509ContentType.Pkcs12);
var withFlagsReimportOfCopiedWithPK = new X509Certificate2(exportOfCopiedWithPkCert, (SecureString)null, keyStorageFlags);
InstallCertInStore(StoreLocation.LocalMachine, withFlagsReimportOfCopiedWithPK);// This one works. Cert has key icon, and text "You have a private key that corresponds to this certificate"
return Task.FromResult(true);
}
最后一个选项确实有效,但它似乎比必要的步骤多得多,这表明我即将定义自己的扩展方法:.ActuallyCopyWithPrivateKey,以替换它的 .NET 框架版本方法。这似乎是错误的。
有没有更好的方法来实现这一点,还是真的需要全部 4 个步骤。
【问题讨论】:
-
这 4 个步骤有什么问题?对我来说看起来不错,我同意你的解决方案。
-
将其导出为字节,然后立即重新导入它,感觉很讨厌。我希望有一个
.SetKeyStorageFlags()方法,或者我可以将它们传递给.CopyWithPK方法,或者在原始构造函数上设置标志会起作用,或者类似的东西。 -
我当然认为是 KeyStorageFlags 有所作为?如果不是,那么这有点说明我的意思......不清楚为什么我们要执行后两个步骤以及为什么结果对象不同。
-
我相信这行:
var copiedWithPKCert = originalCert.CopyWithPrivateKey(privateKeyUsedToGenerateCsr);应该可以工作。当您将证书添加到存储时,CryptoAPI 应将密钥添加到私钥对象中指定的 CSP,将其放在正确的位置并通过存储附加属性进行更新。 -
好的,我现在明白你的问题了。如果在那段时间没有人回答,明天再看看。
标签: private-key x509certificate2 certificate-store