zoukankan      html  css  js  c++  java
  • 捣腾数字签名

    昨天在公司的代码中,看见一个VC项目的Post Build Step会用signtool给项目生成的exe添加数字签名,而exe的某块代码会调用WinVerifyTrust这个Windows API来验证exe自己的数字签名。正好这几天稍微闲暇一些,在好奇心的驱使下便开始捣鼓起数字签名来。经过一天终于有点收获,大致理解数字签名是怎么一回事,也对公司代码的那两块地方比较理解了,于是做个小结。

      首先推荐读读《算法导论》31.7节The RSA public-key crptosystem的第一小节:Public-key cryptosystems,对公钥密码系统的框架做个了解,当然也可以到网上搜类似的介绍性文章。这里不用知道任何数学公式,但要理解整个系统的逻辑流程和设计思想,尤其要理解私钥、公钥的概念,并且要知道:一个消息经公钥和私钥两次编码还是消息本身,且既可以用公钥先编码,也可以用私钥先编码。在这里我还弄明白了:虽然加密和数字签名这两种手段都可以基于同样的公钥密码系统,但它们的目的和工作流程是不一样的——前者是防窃听,后者是验真伪。

      接下来就是捣腾Windows上的数字签名工具,实践一下。signtool是Windows SDK自带的命令行工具,用于对文件进行数字签名,也可用于验证文件和时间戳文件中的签名。公司的那个VC项目使用了如下命令对exe进行数字签名:

    signtool /a <生成的exe>

      不过我用同样的命令在自己家电脑上给一个exe签名,却总是得到“SignTool Error: No certificates were found that met all the given criteria”的错误。捣鼓了半天才知道,如果是自己测试的话,要先用makecert、cert2spc和pvk2pfx制作一个同时包含私钥和公钥的pfx格式的证书文件,然后用pfx文件给exe签名,或者将pfx导入证书库中,让signtool自己去搜可用的证书。可参考《makecert制作数字证书》这篇文章。为了模拟公司项目,我采用了导入证书库的做法,具体来说是这样:

      1、用makecert制作自己的根证书:

     E:Temp>makecert -n "CN=ZzxiangRoot" -r -sky signature -sv ZzxiangRoot.pvk ZzxiangRoot.cer

    Succeeded

    因为我明确是要给二进制文件制作签名,所以要加上-sky signature选项。于是E:Temp目录下就回生成两个文件:私钥证书ZzxiangRoot.pvk和公钥证书ZzxiangRoot.cer。

    2、用cert2spc将公钥证书转换为软件发布者证书,即spc文件:

    E:Temp>cert2spc ZzxiangRoot.cer ZzxiangRoot.spc
    Succeeded

    3、用pvk2pfx将公钥证书和私钥证书合并成一个PFX格式的证书文件:

    E:Temp>pvk2pfx -pvk ZzxiangRoot.pvk -spc ZzxiangRoot.spc -pfx ZzxiangRoot.pfx

    4、双击ZzxiangRoot.pfx将其导入证书库中。在“证书导入向导”中,一路点击“下一步”,直到“证书存储”步骤,选择“将所有的证书放入下列存储”:

    点击“浏览”,在弹出的对话框中选择“个人”->“确定”。

    为什么要选择“个人”呢?可以参见signtool的sign子命令的/s选项的说明:“指定要在搜索证书时打开的存储区。 如果未指定该选项,则打开My存储。”这里的“My”就是“个人”。

    然后就可以一路“下一步”到导入完成了。我们可以到计算机的管理控制台确认。在开始菜单中搜索并运行mmc。在mmc界面中,选择“文件”->“添加删除管理单元”。在弹出的“添加删除管理单元”对话框中,在左边的“可用的管理单元”中选择“证书”:

    点击中间的“添加”按钮,在弹出的对话框中选择“我的用户帐户”或“计算机用户帐户”,再点击“完成”:

    就将“证书”节点添加到“所选管理节点”中了:

    点击“确定”,回到管理控制台主界面中,在左边的树控件中展开“证书 - 当前用户”->“个人”,选择“证书”节点,就可以看见已经导入的ZzxiangRoot证书。

    双击ZzxiangRoot,可以看见证书对话框里写着“您有一个与该证书对应的私钥”。对话框里还写着“此CA根目录证书不受信任。要启用信任,请将该证书安装到‘受信任的根证书颁发机构’存储区”。后面会讲到这一点。

    5、现在可以使用signtool命令给exe签名了:

    E:Temp>signtool sign /a Test.exe
    Done Adding Additional Store
    Successfully signed: Test.exe

    可以加上/v查看更细致的输出:

    E:Temp>signtool sign /a /v Test.exe
    The following certificate was selected:
        Issued to: ZzxiangRoot
        Issued by: ZzxiangRoot
        Expires:   Sun Jan 01 07:59:59 2040
        SHA1 hash: 3361BBBD366687FD80B201F1346561C6E4936263

    Done Adding Additional Store
    Successfully signed: Test.exe

    Number of files successfully Signed: 1
    Number of warnings: 0
    Number of errors: 0

      接下来就是要验证exe的签名。按照公钥密码系统的设计思路,这一步可以在任意机器上进行。公司代码用的是WinVerifyTrust函数。其实也可以继续用signtool工具,命令格式是

    signtool verify /pa <需要验证的exe>

      注意必须要加上/pa选项,否则signtool会使用针对Windows驱动程序的签名验证策略。

      不过现在直接用signtool verify /pa Test.exe的话,会得到“SignTool Error: A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider”的错误。这是因为验证用的计算机没有将ZzxiangRoot公钥证书添加到之前提到的“受信任的根证书颁发机构”。要做这一步的话,需要将公钥证书ZzxiangRoot.cer拷贝到验证机上,然后双击该cer文件,在弹出的证书对话框中选择“安装证书”。接下来和之前的导入证书操作一样,只是在“证书存储”这一步,需要选择将证书存储在“受信任的根证书颁发机构”存储区,而不是之前的“个人”存储区中。

      现在可以进行验证了:

    E:Temp>signtool verify /pa Test.exe

    Successfully verified: Test.exe

    也可以加上/v查看更细致的输出:

    E:Temp>signtool verify /pa /v Test.exe


    Verifying: Test.exe
    Hash of file (sha1): 8D3C56FBE8BB11FB760B729FF8F801DDBA7C3B59

    Signing Certificate Chain:
        Issued to: ZzxiangRoot
        Issued by: ZzxiangRoot
        Expires:   Sun Jan 01 07:59:59 2040
        SHA1 hash: 3361BBBD366687FD80B201F1346561C6E4936263

    File is not timestamped.
    Successfully verified: Test.exe

    Number of files successfully Verified: 1
    Number of warnings: 0
    Number of errors: 0

       使用WinVerifyTrust函数进行验证的方法可以参见MSDN的这个例子。这个例程可以直接拷贝下来用的,只是需要注意,要将它作为C++文件来编译,而不是纯C文件,否则会编译不过。

      说起来真是挺搞笑。虽然我的大学宣称自己的特色是信息安全,但大学毕业后五年来,这还是我第一次认真研究信息安全相关的技术。

    参考:http://blog.csdn.net/zzxiang1985/article/details/9156191

    https://msdn.microsoft.com/en-us/library/windows/desktop/aa382384(v=vs.85).aspx

    ----------------------------------------------------------------------------------------

    上面提到的几个命令都是系统中的,打开cmd之后输入命令默认是找不到路径的。

    需要执行脚本设置:

    A:Program Files (x86)Microsoft Visual Studio 10.0VCinvcvars32.bat

    A:Program Files (x86)Microsoft Visual Studio 10.0VCinamd64vcvars64.bat

    A:Program Files (x86)Microsoft Visual Studio 10.0VCvcvarsall.bat

    可以在当前目录下建一个init.bat内容如下:

    "A:Program Files (x86)Microsoft Visual Studio 10.0VCinvcvars32.bat"


  • 相关阅读:
    Android(java)学习笔记62:android.intent.action.MAIN 与 android.intent.category.LAUNCHER 理解
    Android(java)学习笔记61:Android中的 Application类用法
    Android(java)学习笔记60:继承中父类 没有无参构造
    Android(java)学习笔记59:类继承的 注意事项
    POJ 3740 Easy Finding
    POJ 2676 Sudoku
    FZU 2184 逆序数还原
    ZOJ 1926 Guessing Game
    POJ 2656 Unhappy Jinjin
    HDU 2604 Queuing
  • 原文地址:https://www.cnblogs.com/findumars/p/4820340.html
Copyright © 2011-2022 走看看