我正在考虑允许用户选择将用于我们一项服务的SSL的证书,该用户最初需要选择商店名称,并且证书列表将显示在下拉列表中,我删除了在阅读此article之后,该证书应仅来自本地计算机下的 MY 商店位置。在检查了几篇文章之后,我创建了以下代码
using (var store = new X509Store(StoreName.My,StoreLocation.LocalMachine))
{
store.Open(OpenFlags.ReadOnly);
var certificates = store.Certificates;
foreach (var c in certificates)
{
bool isSslCompatible = false;
bool ekuExists = false;//when this value does not exist, certificate can be used for all purposes [ https://tools.ietf.org/html/rfc3280#section-4.2.1.13 ]
if (c.HasPrivateKey)//only chose those that have a private key
{
foreach (X509Extension extension in c.Extensions)
{
if (extension.Oid.Value == "2.5.29.37")//[ Friedlname = Enhanced Key Usage, names are localised, firendly name cannot be used
{
ekuExists = true;
X509EnhancedKeyUsageExtension ext = (X509EnhancedKeyUsageExtension) extension;
OidCollection oids = ext.EnhancedKeyUsages;
foreach (Oid oid in oids)
{
if (/*oid.FriendlyName == "Server Authentication" || -- cannot be used as friendly names are localised*/
oid.Value == "1.3.6.1.5.5.7.3.1")
{
isSslCompatible = true;
}
}
}
}
if (isSslCompatible || !ekuExists)//add only if value is ssl compatible
{
SSLCertficate certificate = new SSLCertficate();
certificate.CertificateHash = c.GetCertHash();
certificate.CertificateHashString = c.GetCertHashString();
certificate.CertificateThumbPrint = c.Thumbprint;
certificate.FriendlyName = c.FriendlyName;
certificate.SubjectName = c.Subject;
certificate.HasPrivateKey = c.HasPrivateKey;
sslCertificates.Add(certificate);
}
}
}
上述代码的问题是,它看不到证书并且具有“所有预期用途”,我不确定如何获得这些证书,
检查属性窗口,我得到以下信息, ,上面的代码似乎无法检测到该证书,在IIS下进行检查,我能够将此特定的证书用于Https,在检测有效SSL证书的代码方面我还缺少什么?
答案 0 :(得分:2)
MMC UI有点误导。意思是“启用证书已经要求的所有目的”。
在您的过滤代码中,您需要提供一个EKU扩展名并具有TLS服务器身份验证目的。
IETF RFC 3280 section 4.2.1.13说
如果存在扩展名,则只能使用证书 用于指示的目的之一。如果有多个目的 表示应用程序不需要识别所有指定用途, 只要存在预期目的。证书使用 应用程序可能要求在 以便证书可以被该应用程序接受。
这通常是指“如果没有扩展名,则该证书被视为对所有目的均有效”。 TLS RFC似乎没有专门引用id-kp-serverAuth
EKU,这意味着要检查它是“通过严格的约定”应用程序约定。
有不同的规范可以覆盖“对所有目的都有效”的隐式评估,例如IETF RFC 3161(受信任的时间戳记)第2.3节:
相应的证书必须仅包含 [RFC2459]节中定义的扩展密钥用法字段扩展 4.2.1.13,KeyPurposeID的值为:
id-kp-timeStamping。此扩展名必须是至关重要的。
但是,再次,TLS从来没有真正谈论它。
因此您需要更加复杂。 Web浏览器使用的逻辑是if (!hasEkuExtension || hasServerAuthEku)
,而不是您的if (hasServerAuthEku)
。
此外,您应该(几乎)始终按Oid
而不是Value
来比较FriendlyName
个对象。 FriendlyName
已本地化,因此您的代码只能在英语系统上可靠地运行。 Oid.Value
值是证书中实际存在的(文本形式)。 (唯一的例外是Value为null时,因为这意味着API试图表示一个没有定义OID的值(并且由于Curve25519而仅在ECCurve中才发生))。