为啥 CertificateRequest 的 PublicKey.Key 与私钥不在同一个提供者中?
Posted
技术标签:
【中文标题】为啥 CertificateRequest 的 PublicKey.Key 与私钥不在同一个提供者中?【英文标题】:Why is PublicKey.Key of CertificateRequest isn't in the same provider as the private key?为什么 CertificateRequest 的 PublicKey.Key 与私钥不在同一个提供者中? 【发布时间】:2020-10-25 12:38:35 【问题描述】:我使用这个创建一个证书请求:
CertificateRequest req = new CertificateRequest(
"cn=test",
Key,
HashAlgorithmName.SHA256,
RSASignaturePadding.Pkcs1);
key
是从 CSP 设置的:
ProviderName:“Utimaco CryptoServer CSP”
KeyContainerName: "默认容器"
但在调试时我发现req.PublicKey.Key.CspKeyContainerInfo
指的是不同的提供者:
ProviderName:“Microsoft 增强的 RSA 和 AES 加密提供程序”
KeyContainerName:空
当我尝试获取Exportable
值时:
var isExportable = ((RSACryptoServiceProvider)req.PublicKey.Key).CspKeyContainerInfo.Exportable;
它抛出一个CryptographicException
:密钥不存在
我不明白为什么私钥和公钥分别存储在不同的提供者中?! 还是这意味着别的什么?
【问题讨论】:
【参考方案1】:TL;DR 提供程序设置为通用 RSA 提供程序,但请注意 KeyContainerName
是 null
。这只是因为它只是在内存中生成,并没有存储在任何地方。
证书签名请求 (CSR) 是在应用程序中创建的公共文件。此时与私钥的“唯一”关系是:
-
需要包含公钥;
需要用私钥签名(以表明您在创建 CSR 时有权访问它,并保护它不被更改);
为此,它从密钥对加载公钥,从中创建未签名的 CSR,然后使用私钥对其进行签名。 除此之外,CSR 仅用于请求实际证书。 无需将 CSR/私钥存储在 HSM 中。 这反映在(例如)PKCS#11 根本没有任何 CSR 的概念。
请注意,丢失 CSR 的风险很小,您可以随时重新创建一个。此外,如果有人在您将 CSR 发送到 CA 之前到达 CSR,那么它将被签名验证捕获(或者您会使用错误的公钥获得无效证书,请始终确保已验证并发送尽快提交 CSR)。
当您收到实际证书时,将其存储在 HSM 中是有意义的。通常存储到根的整个证书链,因为协议中通常需要中间证书(包括例如 TLS 和 CMS)。毕竟,它们用于每个签名创建 - 希望您不会将私有对用于您创建它的 PKI 之外的任何其他东西。
许多 HSM 确实提供了存储通用数据的规定。尽管您可以在其中放置 CSR,但它只是一个通用存储;密钥存储本身不会将 CSR 与私钥链接起来,因此您不妨将其保存在存储中,希望在某个受保护的位置,只有您的密钥管理器具有写入权限。
【讨论】:
好点,但这对 API 的设计有何影响,即公钥的Exportable
属性会引发“密钥不存在”异常?
我的意思是,如果这是一种自然行为(将公钥存储在内存中),为什么不直接返回 false
,因为抛出异常可以防止例如序列化它。
我不知道,但“可导出”与否肯定也是一个安全属性,即如果它是可导出的,那么 HSM 可能实际上并没有保护密钥。所以大概它被设置为“true”只是为了表明它们不受保护。但是,由于它不在任何密钥库中,因此您仍然会遇到异常。但这是对这种情况的推理,我必须承认。以上是关于为啥 CertificateRequest 的 PublicKey.Key 与私钥不在同一个提供者中?的主要内容,如果未能解决你的问题,请参考以下文章
CertManager Letsencrypt CertificateRequest “未能执行自检 GET 请求”
如何将 CSR 文本文件转换为 .NET Core/Standard CertificateRequest 以进行签名?