X509FindType.FindBySubjectDistinguishedName 找不到我的证书?
X509FindType.FindBySubjectDistinguishedName not finding my certificate?
我正在制作一个自签名的X509证书如下:
public X509Certificate2 GenerateSelfSignedCertificate(Guid customerId)
{
var distinguishedName = GetDistinguishedName(customerId);
var rsa = RSA.Create(KeySize);
var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithm, Padding);
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
request.CertificateExtensions.Add(new X509KeyUsageExtension(
X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.DataEncipherment |
X509KeyUsageFlags.NonRepudiation, false));
var cert = request.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.Add(CertificateLifespan));
return cert;
}
然后我使用此方法生成证书并使用以下方法存储它:
public void StoreCertificate(X509Certificate2 certificate)
{
using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
store.Close();
}
接下来,我尝试使用以下方法从证书存储中获取证书:
public X509Certificate2 FetchPrivateCertificate(Guid customerId)
{
var distinguishedName = GetDistinguishedName(customerId);
using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
var certs = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, distinguishedName, false);
store.Close();
var privateCert = certs.OfType<X509Certificate2>().FirstOrDefault(x => x.HasPrivateKey);
return privateCert;
}
...使用相同的 customerId
,此结果始终为空。它甚至没有检查证书是否有私钥,证书集合总是空的。专有名称的生成方式完全相同。证书肯定在证书库中。
我错过了什么?
更新
根据请求,我添加了专有名称的生成方式:
private string GetDistinguishedName(Guid customerId)
{
var domain = IPGlobalProperties.GetIPGlobalProperties().DomainName;
var domainDistinguishedName = string.Join(",DC=", domain.Split("."));
var distinguishedName = $"DC={Environment.MachineName},DC={domainDistinguishedName},O={customerId}";
return distinguishedName;
}
问题(如评论中所指出)是您的 GetDistinguishedName
returns 未格式化的 x.500 字符串足以构建 X.500 名称,但不足以进行搜索,因为搜索函数对输入字符串和 *formatted* X.500 字符串进行序号和不区分大小写的比较。也就是说,您可以使用这些字符串格式来构建 X.500 名称:
CN=my common name,O=example LLC
CN = my common name,O = example LLC
CN= my common name, O =example LLC
<other variations>
CryptoAPI 使用 X.500 格式化程序将任何有效的 X.500 字符串格式化为外观一致的字符串,例如将 RDN 属性名称大写,删除 =
字符周围的 space,在 RDN 定界符后添加 space 甚至更多,该函数可能会重新排列字符串中的 RDN 属性。当通过 X.500 名称搜索证书时,您必须将 formatted/sanitized X.500 名称传递给搜索功能。最简单的方法是按如下方式更新 GetDistinguishedName
函数:
private string GetDistinguishedName(Guid customerId)
{
var domain = IPGlobalProperties.GetIPGlobalProperties().DomainName;
var domainDistinguishedName = string.Join(",DC=", domain.Split("."));
var distinguishedName = $"DC={Environment.MachineName},DC={domainDistinguishedName},O={customerId}";
return new X500DistinguishedName(distinguishedName).Name;
}
即返回前强制格式化字符串。
p.s。 DC={Environment.MachineName}
使用了不正确的 RDN 属性。 DC代表domainComponent
。机器名无论如何都不是域组件。使用 CN
(通用名称)属性来存储机器名称。而 O
代表 Organization
。我怀疑它也被滥用了,因为 customerId
几乎没有组织名称(只是一个假设)。您应该在 subject/issuer 字符串中使用正确的 RDN 类型。
我正在制作一个自签名的X509证书如下:
public X509Certificate2 GenerateSelfSignedCertificate(Guid customerId)
{
var distinguishedName = GetDistinguishedName(customerId);
var rsa = RSA.Create(KeySize);
var request = new CertificateRequest(distinguishedName, rsa, HashAlgorithm, Padding);
request.CertificateExtensions.Add(new X509BasicConstraintsExtension(false, false, 0, false));
request.CertificateExtensions.Add(new X509KeyUsageExtension(
X509KeyUsageFlags.DigitalSignature | X509KeyUsageFlags.DataEncipherment |
X509KeyUsageFlags.NonRepudiation, false));
var cert = request.CreateSelfSigned(DateTimeOffset.Now, DateTimeOffset.Now.Add(CertificateLifespan));
return cert;
}
然后我使用此方法生成证书并使用以下方法存储它:
public void StoreCertificate(X509Certificate2 certificate)
{
using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadWrite);
store.Add(certificate);
store.Close();
}
接下来,我尝试使用以下方法从证书存储中获取证书:
public X509Certificate2 FetchPrivateCertificate(Guid customerId)
{
var distinguishedName = GetDistinguishedName(customerId);
using var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.OpenExistingOnly | OpenFlags.ReadOnly);
var certs = store.Certificates.Find(X509FindType.FindBySubjectDistinguishedName, distinguishedName, false);
store.Close();
var privateCert = certs.OfType<X509Certificate2>().FirstOrDefault(x => x.HasPrivateKey);
return privateCert;
}
...使用相同的 customerId
,此结果始终为空。它甚至没有检查证书是否有私钥,证书集合总是空的。专有名称的生成方式完全相同。证书肯定在证书库中。
我错过了什么?
更新
根据请求,我添加了专有名称的生成方式:
private string GetDistinguishedName(Guid customerId)
{
var domain = IPGlobalProperties.GetIPGlobalProperties().DomainName;
var domainDistinguishedName = string.Join(",DC=", domain.Split("."));
var distinguishedName = $"DC={Environment.MachineName},DC={domainDistinguishedName},O={customerId}";
return distinguishedName;
}
问题(如评论中所指出)是您的 GetDistinguishedName
returns 未格式化的 x.500 字符串足以构建 X.500 名称,但不足以进行搜索,因为搜索函数对输入字符串和 *formatted* X.500 字符串进行序号和不区分大小写的比较。也就是说,您可以使用这些字符串格式来构建 X.500 名称:
CN=my common name,O=example LLC
CN = my common name,O = example LLC
CN= my common name, O =example LLC
<other variations>
CryptoAPI 使用 X.500 格式化程序将任何有效的 X.500 字符串格式化为外观一致的字符串,例如将 RDN 属性名称大写,删除 =
字符周围的 space,在 RDN 定界符后添加 space 甚至更多,该函数可能会重新排列字符串中的 RDN 属性。当通过 X.500 名称搜索证书时,您必须将 formatted/sanitized X.500 名称传递给搜索功能。最简单的方法是按如下方式更新 GetDistinguishedName
函数:
private string GetDistinguishedName(Guid customerId)
{
var domain = IPGlobalProperties.GetIPGlobalProperties().DomainName;
var domainDistinguishedName = string.Join(",DC=", domain.Split("."));
var distinguishedName = $"DC={Environment.MachineName},DC={domainDistinguishedName},O={customerId}";
return new X500DistinguishedName(distinguishedName).Name;
}
即返回前强制格式化字符串。
p.s。 DC={Environment.MachineName}
使用了不正确的 RDN 属性。 DC代表domainComponent
。机器名无论如何都不是域组件。使用 CN
(通用名称)属性来存储机器名称。而 O
代表 Organization
。我怀疑它也被滥用了,因为 customerId
几乎没有组织名称(只是一个假设)。您应该在 subject/issuer 字符串中使用正确的 RDN 类型。