如何确保 X509Certificate2 class 不会 return 重复签名证书?
How to ensure X509Certificate2 class does not return duplicate signing certificates?
我有一个 C# windows 表单应用程序。用户键入消息、主题、收件人,并从下拉列表中选择签名证书以使用 X509Certificate2
class 对电子邮件进行签名。
以下是下拉列表 (ComboBox SigningCertList) 填充方式的代码段:
try
{
X509Certificate2[] certs;
certs = CryptoHelper.GetSigningCertificateList();
SigningCertList.Items.AddRange(certs);
SigningCertList.ValueMember = "SerialNumber";
SigningCertList.DisplayMember = "FriendlyName";
SigningCertList.SelectedIndexChanged += new System.EventHandler(SigningCertList_SelectedIndexChanged);
SigningCertList.SelectedItem = 0;
}
症状很奇怪。组合框将显示我的签名证书(从 p12 文件安装)。但是,如果我加载 Windows Certificates MMC 管理单元,我在搜索时找不到它。重新安装证书后,我在 Windows Certificates MMC 管理单元中看到它,现在在下拉列表中复制了它。只有列表中的第二个(或最后一个/最近的)签名证书才真正对其进行签名。
那么如何确保 X509Certificate2
class 不会 return 重复签名证书?
下面是 GetSigningCertificateList() 方法:
`public static X509Certificate2[] GetSigningCertificateList()
{
var list = new List();
int matches = 0;
X509Store localStore = new X509Store(StoreLocation.LocalMachine);
localStore.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
try
{
foreach (X509Certificate2 cert in localStore.Certificates)
{
foreach (X509Extension extension in cert.Extensions)
{
X509KeyUsageExtension usageExtension = extension as X509KeyUsageExtension;
if (usageExtension != null)
{
bool matchesUsageRequirements = ((X509KeyUsageFlags.DigitalSignature & usageExtension.KeyUsages) == X509KeyUsageFlags.DigitalSignature);
if (matchesUsageRequirements)
{
list.Add(cert);
matches += 1;
}
}
}
}
}
finally
{
localStore.Close();
}
X509Store userStore = new X509Store(StoreLocation.CurrentUser);
userStore.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
try
{
foreach (X509Certificate2 cert in userStore.Certificates)
{
foreach (X509Extension extension in cert.Extensions)
{
X509KeyUsageExtension usageExtension = extension as X509KeyUsageExtension;
if (usageExtension != null)
{
bool matchesUsageRequirements = ((X509KeyUsageFlags.DigitalSignature & usageExtension.KeyUsages) == X509KeyUsageFlags.DigitalSignature);
if ((matchesUsageRequirements) && cert.FriendlyName.IndexOf("MYcompanyname.",0) >= 0)
{
list.Add(cert);
matches += 1;
}
}
}
}
}
finally
{
userStore.Close();
}
return list.ToArray();
}
}`
您提到您在 MMC 中看不到证书,但在您的应用程序中看到;并且当您通过 MMC 安装证书时,它会出现两次。这表明您正在使用 MMC 查看用户我的商店(或计算机我的商店),但有问题的证书通常存在于其他位置。
一旦证书在两个不同的商店注册(相同的商店名称,不同的位置 => 不同的商店)然后 Windows 不再认为它是重复的(对于一个,两个实例可以有不同的私钥权限)。因此,虽然您的应用程序有重复项,但(本质上)没有 Windows 或 .NET.
您可以通过标准的重复数据删除策略来防止重复,例如使用 HashSet 而不是 List。如果发行者和序列号相同,默认的 .Equals 检查(由默认比较器执行)将匹配。只要您的证书来自 public CA,那应该是唯一的;但私有 PKI 可以 回收序列号或不保证唯一性。如果您担心,您可以使用自定义比较器,它使用您喜欢的任何匹配逻辑。
所以简单的去重是用list = new HashSet<X509Certificate2>()
替换list = new List<X509Certificate2>()
(尽管你可能应该改变变量名)。
HashSet 仅保留第一个冲突;因此,如果您希望 LocalMachine 成为首选,那么您已经做到了。如果 CurrentUser 获胜,您可能需要调换方块。
另外两件注意事项:
如果证书根本没有密钥使用扩展,则它被认为对所有用途都有效。您的代码不会那样做。 (如果您知道您的应用程序中的 "correct" 证书始终存在,那么就没有问题)
X509Store.Certificates returns 每次调用的新对象;您可以通过对您不需要的证书调用 Dispose 来减少最终确定 return(或 Reset for .NET 4.5.2 and below)。
我有一个 C# windows 表单应用程序。用户键入消息、主题、收件人,并从下拉列表中选择签名证书以使用 X509Certificate2
class 对电子邮件进行签名。
以下是下拉列表 (ComboBox SigningCertList) 填充方式的代码段:
try
{
X509Certificate2[] certs;
certs = CryptoHelper.GetSigningCertificateList();
SigningCertList.Items.AddRange(certs);
SigningCertList.ValueMember = "SerialNumber";
SigningCertList.DisplayMember = "FriendlyName";
SigningCertList.SelectedIndexChanged += new System.EventHandler(SigningCertList_SelectedIndexChanged);
SigningCertList.SelectedItem = 0;
}
症状很奇怪。组合框将显示我的签名证书(从 p12 文件安装)。但是,如果我加载 Windows Certificates MMC 管理单元,我在搜索时找不到它。重新安装证书后,我在 Windows Certificates MMC 管理单元中看到它,现在在下拉列表中复制了它。只有列表中的第二个(或最后一个/最近的)签名证书才真正对其进行签名。
那么如何确保 X509Certificate2
class 不会 return 重复签名证书?
下面是 GetSigningCertificateList() 方法: `public static X509Certificate2[] GetSigningCertificateList() { var list = new List();
int matches = 0;
X509Store localStore = new X509Store(StoreLocation.LocalMachine);
localStore.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
try
{
foreach (X509Certificate2 cert in localStore.Certificates)
{
foreach (X509Extension extension in cert.Extensions)
{
X509KeyUsageExtension usageExtension = extension as X509KeyUsageExtension;
if (usageExtension != null)
{
bool matchesUsageRequirements = ((X509KeyUsageFlags.DigitalSignature & usageExtension.KeyUsages) == X509KeyUsageFlags.DigitalSignature);
if (matchesUsageRequirements)
{
list.Add(cert);
matches += 1;
}
}
}
}
}
finally
{
localStore.Close();
}
X509Store userStore = new X509Store(StoreLocation.CurrentUser);
userStore.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly);
try
{
foreach (X509Certificate2 cert in userStore.Certificates)
{
foreach (X509Extension extension in cert.Extensions)
{
X509KeyUsageExtension usageExtension = extension as X509KeyUsageExtension;
if (usageExtension != null)
{
bool matchesUsageRequirements = ((X509KeyUsageFlags.DigitalSignature & usageExtension.KeyUsages) == X509KeyUsageFlags.DigitalSignature);
if ((matchesUsageRequirements) && cert.FriendlyName.IndexOf("MYcompanyname.",0) >= 0)
{
list.Add(cert);
matches += 1;
}
}
}
}
}
finally
{
userStore.Close();
}
return list.ToArray();
}
}`
您提到您在 MMC 中看不到证书,但在您的应用程序中看到;并且当您通过 MMC 安装证书时,它会出现两次。这表明您正在使用 MMC 查看用户我的商店(或计算机我的商店),但有问题的证书通常存在于其他位置。
一旦证书在两个不同的商店注册(相同的商店名称,不同的位置 => 不同的商店)然后 Windows 不再认为它是重复的(对于一个,两个实例可以有不同的私钥权限)。因此,虽然您的应用程序有重复项,但(本质上)没有 Windows 或 .NET.
您可以通过标准的重复数据删除策略来防止重复,例如使用 HashSet
所以简单的去重是用list = new HashSet<X509Certificate2>()
替换list = new List<X509Certificate2>()
(尽管你可能应该改变变量名)。
HashSet 仅保留第一个冲突;因此,如果您希望 LocalMachine 成为首选,那么您已经做到了。如果 CurrentUser 获胜,您可能需要调换方块。
另外两件注意事项:
如果证书根本没有密钥使用扩展,则它被认为对所有用途都有效。您的代码不会那样做。 (如果您知道您的应用程序中的 "correct" 证书始终存在,那么就没有问题)
X509Store.Certificates returns 每次调用的新对象;您可以通过对您不需要的证书调用 Dispose 来减少最终确定 return(或 Reset for .NET 4.5.2 and below)。