通过MSBuild使用Authenticode证书对每个可执行文件进行签名

Mep*_*toe 9 msbuild certificate team-build authenticode

我有一个Authenticode证书(.pfx),我用它来签署可执行文件.

如何配置Team Build,以便在构建项目时自动签署每个可执行文件(.exe,.dll,...)?

Sha*_*ser 16

这是我们使用的方法:

  1. 卸载WiX项目并选择编辑

  2. 滚动到底部,您可以在其中找到 <Import Project="$(WixTargetsPath)" />

  3. 在其上方添加一个新行:<Import Project="ProjectName.custom.targets" /> 我们使用命名约定"ProjectName.custom.targets",但该文件可以命名为您想要的任何名称.

  4. 创建一个名为ProjectName.custom.Targets的新XML文件,并将以下代码放入其中:

    <?xml version="1.0" encoding="utf-8"?>
    <Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <!-- replace the contents of this with your private test authenticode certificate -->
        <AuthenticodeCertFile Condition="'$(AuthenticodeCertFile)' == ''">$(MSBuildProjectDirectory)\AuthenticodeTest.pfx</AuthenticodeCertFile>
      </PropertyGroup>
    
      <!-- this gets the path to signtool.exe and places it in the _SignToolSdkPath property -->
      <Target Name="_GetSignToolPath">
        <GetFrameworkSdkPath>
          <Output TaskParameter="Path" PropertyName="_SignToolSdkPath" />
        </GetFrameworkSdkPath>
        <PropertyGroup>
          <_SignToolPath>$(_SignToolSdkPath)bin\signtool.exe</_SignToolPath>
        </PropertyGroup>
      </Target>
    
      <!-- This gets a list of all of the "referenced" assembies used by the installer project --> 
      <!-- Unfortunately, I cheated and used an "internal" item list - you could replace this with each specific assembly but it gets complicated if your build output is redirected -->
      <Target Name="_GetSourceAssembliesToSign" DependsOnTargets="ResolveReferences">
        <!-- Kludge - not supposed to target internal items, but there are no other options -->
        <CreateItem Include="@(_ResolvedProjectReferencePaths)">
          <Output ItemName="_SourceAssemblyToSign" TaskParameter="Include" />
        </CreateItem>
      </Target>
    
      <!-- This signs the assemblies in the @(_SourceAssemblyToSign) item group -->
      <!-- Note that it only executes when build output is redirected ie/ on TFS Build or when OutDir is changed -->  
      <!-- Authenticode timestamp is optional - doesn't make sense to timestamp the test certificate -->
      <Target Name="_AuthenticodeSignSourceAssemblies" AfterTargets="BeforeBuild" DependsOnTargets="_GetSignToolPath;_GetSourceAssembliesToSign" Condition="'$(AuthenticodeCertFile)' != '' and '$(OutDir)' != '$(OutputPath)'">
        <Exec Command="&quot;$(_SignToolPath)&quot; sign /f &quot;$(AuthenticodeCertFile)&quot; /p &quot;$(AuthenticodePassword)&quot; /t $(AuthenticodeTimestamp) /v &quot;%(_SourceAssemblyToSign.Identity)&quot;" Condition="'$(AuthenticodeTimestamp)' != ''" />
        <Exec Command="&quot;$(_SignToolPath)&quot; sign /f &quot;$(AuthenticodeCertFile)&quot; /p &quot;$(AuthenticodePassword)&quot; /v &quot;%(_SourceAssemblyToSign.Identity)&quot;" Condition="'$(AuthenticodeTimestamp)' == ''" />
      </Target>
    
      <!-- This signs the MSI file itself -->
      <!-- Note that additional changes may be needed if your CAB files are separate - those would need to be signed as well -->
      <!-- Note that it only executes when build output is redirected ie/ on TFS Build or when OutDir is changed -->  
      <Target Name="_AuthenticodeSignMsi" AfterTargets="SignMsi" DependsOnTargets="_GetSignToolPath" Condition="'$(AuthenticodeCertFile)' != '' and '$(OutDir)' != '$(OutputPath)'">
        <PropertyGroup>
          <_MsiFileToSign>$(TargetDir)%(CultureGroup.OutputFolder)$(TargetName)$(TargetExt)        </_MsiFileToSign>
        </PropertyGroup>
    
        <Exec Command="&quot;$(_SignToolPath)&quot; sign /f &quot;$(AuthenticodeCertFile)&quot; /p &quot;$(AuthenticodePassword)&quot; /t $(AuthenticodeTimestamp) /v &quot;$(_MsiFileToSign)&quot;" Condition="'$(AuthenticodeTimestamp)' != ''" />
        <Exec Command="&quot;$(_SignToolPath)&quot; sign /f &quot;$(AuthenticodeCertFile)&quot; /p &quot;$(AuthenticodePassword)&quot; /v &quot;$(_MsiFileToSign)&quot;" Condition="'$(AuthenticodeTimestamp)' == ''" />
      </Target>
    </Project>
    
    Run Code Online (Sandbox Code Playgroud)

创建一个测试authenticode证书(我们命名为我们的AuthenticodeTest.pfx)并将其放在源代码控制中 - 它的路径在AuthenticodeCertFile属性中设置.要测试它,在命令行运行msbuild并更改OutDir属性 - 即/ msbuild Test.sln/p:OutDir = C:\ Test

如果符合以下条件,则需要进

  • 如果你不想使用"私人"项目组(我被骗了)
  • 如果您不使用WiX项目参考
  • 如果您的cab文件与MSI分开,则还需要对其进行签名

要运行最终构建,请在TFS中选择"Queue New Build".单击"参数",然后展开"高级".在"MSBuild Arguments"下添加/p:AuthenticodeCertFile=ProductionCertFile.pfx /p:AuthenticodePassword=Secret.请注意,这可能不是完全安全的 - 让构建代理在不检入PFX文件的情况下查找PFX文件并且可以在构建输出中记录密码可能会很棘手.或者,您可以为此创建一个特殊的锁定构建代理,或者在命令行本地运行构建 - 但显然这不是一个"干净的房间"环境.可能值得专门为此目的创建一个特殊的锁定"干净"服务器.

  • 在堆栈溢出问题*[如何安全地存储.pfx密码以在MSBuild中使用?]中描述了避免在项目/ MSBuild文件中使用*纯文本*的密码的方法.(http://stackoverflow.com/问题/ 17710357)*.基本上,它使用Windows证书存储区和*signtool.exe*的*/sha1*选项.然后将安全性绑定到具有相关证书的证书存储的用户帐户. (4认同)

MSa*_*ers -5

不。

您不希望自动签署构建。无论如何,大多数构建都不需要签名;它们仅用于自动化测试。某些构建可能会交给您的内部测试人员。但只有您实际在组织外部发布的构建才需要 Authenticode 签名。

在这种情况下,您无论如何都应该在签名后进行手动验证步骤。因此,手动签名不会在发布过程中插入额外的手动步骤,并且将其自动化可以节省很少的时间。作为交换,您的组织中流通的签名文件将会少得多,并且您可以对这些文件做出更有力的保证。

  • 我不同意“懒得”签字。我们在产品中提供了 100 多个已签名的程序集,并将它们打包到同样已签名的安装程序中。不自动化这将是疯狂的。测试您的实际发布产品比测试与之“类似”的产品要好得多,而且如果您的所有安装程序都经过混淆和签名,这样未受保护的副本就不会泄漏到野外,这会更安全。我们还经营一个敏捷商店,因此任何构建(好的)都可能是发布。(虽然我们没有签署 CI 构建,但这不会生成实际用于任何用途的 exe) (15认同)
  • 不每次都签署所有内容听起来很合理。但是,我们需要建立一个自动化流程来签署软件的发布版本。此外,为了通过 Microsoft 平台测试进行验证,每个 .exe、.dll 和 .msi 都需要进行签名。我们有一个自动化流程,可以获取当前源代码、自动版本化它们、构建它们、创建许可证和目录结构、将所有内容打包到 MSI 中、将文档放入文件夹中,最后压缩所有内容以进行分发。我们只需为签名部分添加另一个构建脚本(MS Build -&gt; Team Build)。但如何呢? (2认同)