代码改变世界

3.6 延迟签名

2011-12-06 10:31  iRead  阅读(290)  评论(0编辑  收藏  举报

  本章前面讲过如何使用SN.exe工具来生成公钥/私钥对。这个工具在生成密钥时,会调用Windows提供的Crypto API。密钥可存储到文件或者其他存储设备中。例如,大企业(比如Microsoft)会将自己的私钥保存到一个硬件设备中,再将这个硬件设备锁到一个保险库中。公司里只有少数几个人才能访问到私钥。这个措施可以防止私钥泄漏,并保证了密钥的完整性。当然,公钥是完全公开的,可以自由分发。

  当你准备好对自己的强命名程序集进行打包时,必须使用受到严密保护的私钥对它进行签名。然而,在开发和测试程序集时,访问这些受到严密保护的私钥可能有些费事儿。有鉴于此,.NET Framework提供了对延迟签名(delayed signing的支持,这个技术有时也成为部分签名(partial signing。延迟签名允许你只用公司的公钥来生成一个程序集,暂时不用私钥。由于使用了公钥,引用了你的程序集的那些程序集会在它们的AssemblyRef元数据表的记录项中嵌入正确的公钥值。另外,它还使程序集能正确存储到GAC的内部结构中。当然,不用公司的私钥对文件进行签名,便无法实现防篡改保护。这是由于无法对程序集的文件进行哈希处理,无法在文件中嵌入一个数字签名。然而,失去这种保护不是一个大问题,因为只是在开发阶段才延迟签名。打包和部署程序集时,肯定是会签名的。

  为了实现延迟签名,你需要获取存储在一个文件中的公钥值,将文件名传给用于生成程序集的任何实用程序。(如本章签名所述,可以使用SN.exe的-p开关从包含一个公钥/私钥对的文件中提取一个公钥值。)另外,还必须让工具知道你想延迟对程序集的签名,暂时不提供一个私钥。如果使用C#编译器,可以指定/delaysign编译器开关。如果使用Visual Studio,需打开项目属性对话框,然后在“签名”选项卡中勾选“仅延迟签名”。如果使用AL.exe,可以指定/delay[sign]命令行开关。

  编译器或AL.exe一旦检测到要对一个程序集进行延迟签名,就会生成程序集的AssemblyDef清单记录项,其中将包含程序集的公钥。公钥使程序集能正确地放到GAC中。另外,这也不妨碍引用了这个程序集的其他程序集的正确生成。在进行引用的程序集的AssemblyRef元数据表记录项中,会包含(被引用程序集)的正确公钥。创建程序集时,会在生成的PE文件为RSA数字签名预留空间(实用程序能根据公钥大小来判断需要预留多大的空间)。要注意的是,文件内容不会在这个时候进行哈希处理。

  目前生成的程序集没有一个有效的签名。将程序集安装到GAC中的尝试会失败,因为尚未对文件内容执行哈希处理—文件表面上已被篡改了。在需要将程序集安装到GAC的每一台机器上,都必须禁止系统验证程序集文件的完整性。为此,要使用SN.exe实用程序,并指定-Vr命令行开关。用这个开关执行SN.exe,程序集的任何文件在运行时加载时,CLR都会跳过其哈希值的检查。在内部,SN的-Vr开关会将程序集的身份添加到一下注册表子项中:

  HEKY_LOCAL_MACHINE\SOFTWARE\Microsoft\StrongName\Verification

重要提示:使用会修改注册表的任何 一个实用程序时,请确保在64位机器上运行的是实用程序的64位版本。32位x86实用程序默认安装到C:\Program Files(x86)\Microsoft SDKs\Windows\v7.0A\bin\NETFX4.0 Tools目录,而64位x64实用程序安装到C:\Program Files(x86)\Microsoft SDKs\Windows\v7.0A\bin\NETFX 4.0 Tools\x64目录。

  结束一个程序集的开发和测试之后,需要正式对其进行签名,以便打包和部署它。为了对程序集进行签名,要再次使用SN.exe实用程序,但这一次换用-R开关,并指定包含了私钥的文件的名称。-R开关指示SN.exe对文件内容进行哈希处理,用私钥对其进行签名,并将RSA数字签名嵌入文件之前预留的空间。经过这一步之后,就可以部署完全签好名的程序集。在开发和测试机器上,不要忘记使用SN.exe的-Vu或-Vx命令行开关来重新启用对这个程序集的验证。下面总结了使用延迟签名技术开发程序集的步骤:

  1. 开发程序集期间,获取只包含你的公司的公钥的一个文件,使用/keyfile和/delaysign编译器开关编译程序集:Csc /keyfile:MyCompany.PublicKey /delaysign MyAssembly.cs
  2. 生成程序集之后,执行以下命令,使CLR暂时信任程序集的内容,不对它进行哈希处理,也不对哈希值进行比较。这使程序集能顺利安装到GAC(如果有必要的话)。现在,可以生成引用了这个程序集的其他程序集,并可随意测试程序集。注意,在每台开发用的机器上,以下命令行都只需执行一次,不必在每次生成程序集时都重复这一步:SN.exe –Vr MyAssembly.dll
  3. 准备好打开和部署程序集时,请获取你的公司的私钥,然后执行以下命令。如果愿意,可以将这个新版本安装到GAC中。但是,只有在完成了第4步之后,才能把它安装到GAC中。  SN.exe –R MyAssembly.dll MyCompany.PrivateKey
  4. 为了在实际环境中测试,请执行以下命令行,重新启用对这个程序集的验证:SN –Vu MyAssembly.dll

  本节开头指出,大企业会把它们的密钥对放到硬件设备(比如智能卡)中。为了确保这些密钥的安全性,密钥值绝对不能持久存储在一个磁盘文件中。“加密服务提供程序”(Cryptographic Service Provider, CSP)提供了对这些密钥的位置进行抽象的容器。以Microsoft使用的CSP为例,一旦访问它提供的容器,就会自动从一个硬件设备中获取私钥。

  如果公钥/私钥对在一个CSP容器中,必须为CSC.exe、AL.exe和SN.exe程序指定不同的开关。编译时(CSC.exe),要指定/keycontainer开关,而不是/keyfile开关;链接时(AL.exe),要指定/keyname开关,而不是/keyfile开关;使用强名称程序(SN.exe)对一个延迟签名的程序集进行重新签名时,要指定-Rc开关,而不是-R开关。SN.exe提供了另外几个开关让开发人员与CSP互动。

重要提示:打包一个程序集前,只要你希望对它执行其他任何操作,延迟签名都非常有用。例如,可能想要对自己的程序集运行一个混淆器(obfuscator)程序。程序集在完全签名后,便不能再对它进行混淆器,否则哈希值就不正确了。所以,要想混淆一个程序集文件,或者进行其他形式的“生成后”(post-build)操作,就应该使用延迟签名,执行所有必要的“生成后”操作,再用-R或-Rc开关运行SN.exe,最终完成对程序集的签名。