在Windows里,我们可以通过certmgr.msc查看和管理系统证书,这个工具是Windows自带的。
然而,如果我们希望在UWP应用中查看这些证书,该怎么做呢?
首先,我所介绍的方法其实不仅仅适用于UWP,事实上这是来自于我的一个WPF应用里的。正因为微软发布了.NET Standard 2.0标准,允许我们跨WPF以及UWP应用使用同一套代码,这就是我为何能够最终完成一个UWP版本的demo。
样例工程可以在我的GitHub找到 https://github.com/EdiWang/Cert-Scanner
解下来看看代码,核心代码如下:
需要引用的命名空间是System.Security.Cryptography.X509Certificates,如果你希望亲自实验这段代码,请记得引用这个命名空间。
public class SystemStorageCertificationScanner : CertificationScanner
{
public override IEnumerable<CertInfo> ScanCertificates()
{
foreach (StoreLocation loc in Enum.GetValues(typeof(StoreLocation)))
{
foreach (StoreName n in Enum.GetValues(typeof(StoreName)))
{
X509Store store = new X509Store(n, loc);
store.Open(OpenFlags.ReadOnly);
foreach (var storeCertificate in store.Certificates)
{
var certInfo = new CertInfo()
{
Subject = storeCertificate.Subject,
FriendlyName = storeCertificate.FriendlyName,
Issuer = storeCertificate.Issuer,
Version = storeCertificate.Version,
Thumbprint = storeCertificate.Thumbprint,
StoreLocation = loc.ToString(),
ExpDate = DateTime.Parse(storeCertificate.GetExpirationDateString()),
Abstract = storeCertificate.ToString()
};
yield return certInfo;
}
store.Close();
}
}
}
}
这个例子里,StoreLocation 是一个枚举类型,只包含2个成员: CurrentUser, LocalMachine
StoreName 是另一个枚举,表示不同种类的证书的类别名称,成员如下:
public enum StoreName
{
AddressBook = 1,
AuthRoot = 2,
CertificateAuthority = 3,
Disallowed = 4,
My = 5,
Root = 6,
TrustedPeople = 7,
TrustedPublisher = 8,
}
解下来,我们就可以通过遍历每一个X509Store对象来获取它存储的证书。但请注意,每次操作我们都必须打开(open)和关闭(close)X509Store对象。
CertInfo 是我写的一个自定义类型,目的是为了让更加易于使用和显示证书信息。
public class CertInfo
{
public string Subject { get; set; }
public string FriendlyName { get; set; }
public string Issuer { get; set; }
public string Thumbprint { get; set; }
public int Version { get; set; }
public string StoreLocation { get; set; }
public DateTime ExpDate { get; set; }
public bool IsExpired => ExpDate < DateTime.Now;
public string Abstract { get; set; }
}
为了让代码设计更加装逼,我添加了接口和抽象类。这些仅供代码设计参考,实际上如果你想直接了当写一个读取证书的逻辑,这些是没必要的。
public interface ICertificationScanner
{
IEnumerable<CertInfo> ScanCertificates();
}
public abstract class CertificationScanner : ICertificationScanner
{
public abstract IEnumerable<CertInfo> ScanCertificates();
}
我建立的UWP引用使用了 Windows Template Studio, 它提供了Telerik Data Grid控件,可以方便我们显示证书信息。并且我也使用了MvvM模式,在这里我就不讲解具体步骤了,因为和本文话题无关。
假设我们已经在应用里引用了Telerik Data Grid,解下来最直观的做法就是加一行XAML代码:
<tg:RadDataGrid ColumnDataOperationsMode="Flyout" x:Name="grid" ItemsSource="{x:Bind ViewModel.Source}" />
然后在ViewModel里获取数据
public class SystemCertsViewModel : ViewModelBase
{
public SystemStorageCertificationScanner SysCertificationScanner { get; set; }
public SystemCertsViewModel()
{
SysCertificationScanner = new SystemStorageCertificationScanner();
}
public ObservableCollection<CertInfo> Source => SysCertificationScanner.ScanCertificates().ToObservableCollection();
}
在这个例子里,ToObservableCollection是我的一个UWP助手库提供的方法,可以通过NuGet安装:
PM> Install-Package Edi.Uwp.Helpers
现在,运行结果就是
最后,需要完整样例代码,可以在我的GitHub找到:https://github.com/EdiWang/Cert-Scanner