一、问题来由
通常我们通过Visual Studio编写的winform程序直接编译之后是一个exe程序,若有引用到第三方dll那么在默认的debug目录下应该会包含一个exe程序和若干的dll,那么生产环境通常的做法是使用ClickOnce发布程序或者是打包成安装文件(web安装部署与winform同理)来部署。
当前要求是要在每次打开程序时读取注册表的相关信息,主要用于检测当前程序是否注册(客户要求程序需要通过读取的机器码生成注册码),若没有注册的机器需要添加注册码之后并在注册表内更新,操作注册表信息在vista以下版本是不会有问题的,但是在windows系统vista及以上版本是需要管理员权限才可以操作注册表信息的,那么也就是程序必须主动以管理员权限运行,在vista及以上版本有加入UAC(用户账户控制) 的机制,我们可以通过添加新建项->应用程序清单文件(如何主动请求管理员权限)来达到每次运行时主动请求管理员权限以执行我们后续的注册表操作。
那么问题来了,在我们运行程序时会弹出UAC(用户账户控制)界面询问是否以管理员权限运行,若以上步骤都有做过的朋友应该对这幅图不陌生了。
很显然,最亮是 ....发布者:未知
我刚开始看到此图的时候想到的是一定是我编译程序哪漏了一步之类的...于是无尽的度娘和谷歌..最终发现是数字证书问题
二、想要的效果
虽然没太大的实质性作用(可能我不知道),但是最起码来说这样看着要舒服一些....
三、证书究竟是什么
说句实话,我对数字证书也只是知道个大概,这篇文章仅介绍如何让我们的程序有一个自己的证书文件,数字签名是什么?(这个解释很生动也容易理解)
那证书在哪查看呢?最简单的就是右键该程序,有证书签名过的程序,会有个数字签名页,如图
我们运行一个有证书的程序(右键->已管理员身份运行),我们以QQ为例,依次做如下操作查看。
点击->显示详细信息->显示有关此发布者的证书信息,这个时候就可以看到证书的颁发者和颁发给的信息。
可以看到颁发者的信息是:VeriSign Class 3 Code Signing 2010 CA,这类证书我认为应该是系统内本身就存在的。
可以在控制台查看到该证书的详细信息。按以下步骤查看:
1:运行内输入:mmc
2:点击->文件->添加/删除管理单元->可用单元内选择 证书(选择我的用户账户)->确定,再添加一次证书选择(计算机用户)->确定
3:这个时候我们可以在 受信任的根证书颁发机构以及第三方根证书颁发机构 找到上面VeriSign的证书信息。
四、该怎么做呢
通过查阅msdn数字证书相关信息,个人觉得程序的证书要最终发挥作用,应当是将我们自己的证书最终要导入到控制台的受信任的根证书颁发机构,不论可执行程序是在何时注册的数字证书(可能是已经注册好放入安装包,也可能是在安装时注册),这时以管理员运行时就会显示出证书的信息,若没有在受信任的根证书颁发机构,将显示发布者未知。
那现在我们要做的也很明确了:
1:首先我们需要生成一个自己的证书
2:我们要将证书导入到 受信任的根证书颁发机构
那如何生成自己的证书呢?微软提供有Makecert.exe(证书创建工具),也可以使用代码的方式生成,下面介绍如何使用Makecert.exe创建我们的证书
Makecert.exe这个工具只要我们安装了visual studio,使用命令提示符就可以了
在命令提示符内输入
makecert -r -pe -n "CN=你的证书名字" -a sha1 -b 01/01/2012 -e 01/01/2040 -sky exchange -ss my
-ss my:证书生成到个人证书位置,这时我们可以在控制台个人证书位置找到生成的证书了,参数的具体含义查看Makecert.exe
因后续我们需要将证书在安装时导入到客户机器上,所以我们将生成好的证书导出,右键证书->所有任务->导出,如图
我们选择默认的格式导出(.CER)。
现在我们已经有了自己的证书文件,还需要将其导入到 受信任的根证书颁发机构。我们这块使用代码实现将其导入,操作类(X509Certificate2)。
X509Certificate2 cert = new X509Certificate2("逗豆豆.cer"); bool my_import = false; bool root_import = false; if (cert != null) { var store2 = new X509Store(StoreName.My, StoreLocation.CurrentUser); store2.Open(OpenFlags.ReadWrite); if (!store2.Certificates.Contains(cert)) { my_import = true; store2.Add(cert); } var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); store.Open(OpenFlags.ReadWrite); if (!store.Certificates.Contains(cert)) { root_import = true; store.Add(cert); } } StringBuilder sb = new StringBuilder(); if (my_import) { sb.Append("成功导入到个人证书目录\r\n"); } if (root_import) { sb.Append("成功导入到受信任的根证书颁发机构证书目录\r\n"); } if (sb.Length == 0) MessageBox.Show("已经导入过证书"); else MessageBox.Show(sb.ToString());
上面代码将证书导入到了个人证书以及受信任的根证书颁发机构,接下来我们需要对我们的可执行程序进行签名,那签名与生成证书类似,微软也有提供一个SignTool.exe(签名工具),同样打开命令提示符输入:signtool sign /a F:\SignatureDemo.exe,参数的具体含义查看SignTool.exe
这个时候右键管理员身份运行就可以看到我们要的效果便达到了。但是实际项目中可能需要在安装程序的时候将证书导入,所以我们可以添加一个安装类,在重写安装的方法内将证书导入:
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Configuration.Install; using System.Linq; using System.Security.Cryptography.X509Certificates; namespace SignatureDemoInstaller { [RunInstaller(true)] public partial class DemoInstaller : System.Configuration.Install.Installer { public DemoInstaller() { InitializeComponent(); } //-------------重写安装方法------------------------------------------------ public override void Install(IDictionary stateSaver) { base.Install(stateSaver); ImportCert(); } //-------------导入证书---------------------------------------------------- private void ImportCert() { X509Certificate2 cert = new X509Certificate2(Context.Parameters["targetdir"] + "\\Bin\\SityTech.cer"); if (cert != null) { var store2 = new X509Store(StoreName.My, StoreLocation.CurrentUser); store2.Open(OpenFlags.ReadWrite); if (!store2.Certificates.Contains(cert)) { store2.Add(cert); } var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); store.Open(OpenFlags.ReadWrite); if (!store.Certificates.Contains(cert)) { store.Add(cert); } } } } }
五、源代码什么的
关于如何打包以及部署问题,可以参考文章的最顶端有介绍,这里就不再赘述,实际步骤很简单,大家完全可以使用代码生成证书的方式,做到动态生成证书并导入,文章可能看起来排版不这么好,也是给想要深入研究的人一点点小建议,另外使用vs2011之前版本的部署项目,生成的msi文件安装完毕之后,桌面的快捷方式右键指向不到程序目录并且右键也没有管理员身份运行的选项,需要使用Orca工具编辑一下,安装完毕Orca之后右键Msi程序->用Orca编辑,在左边的Tables列表中找到Shortcut表,在右边记录中找到Directory为DesktopFolder的记录,修改该记录的Target属性为 [TARGETDIR]应用程序名称.exe即可。
再另外一下..此文章生成证书仅限于学习交流,正式生产环境下,大家应该去证书颁发机构购买,其实很便宜的...,最后demo和msi编辑工具奉上,算是有点用的话,点下推荐吧。