WiX: проект Digitally Sign BootStrapper

У меня есть проект, для которого я создал файл msi WiX. У меня также есть загрузочный файл WiX (exe файл), который проверяет наличие С++ 2005, устанавливает его, если не найден, а затем устанавливает пакет msi. Мой проект включает в себя Crystal Reports как файл msm, который установлен с помощью msi, но для корректной установки требуется С++ 2005.

В проекте MSI я включил следующее событие post build для цифровой подписи файла msi.

  sign  /f "$(ProjectDir)\myPFXFile.pfx" /p mySecretKey/d "My Program" /t http://timestamp.verisign.com/scripts/timstamp.dll /v "MyProgram.msi"

Если я устанавливаю только msi, он правильно идентифицирует издателя при запросе повышенного разрешения на установку.

Я попытался добавить одно и то же событие post-build в проект bootstrapper следующим образом:

  sign  /f "$(ProjectDir)\myPFXFile.pfx" /p mySecretKey/d "My Program" /t http://timestamp.verisign.com/scripts/timstamp.dll /v "MyProgram Setup.exe"

Когда я пытаюсь установить exe файл, он правильно идентифицирует Publisher, но затем не может установить из файла журнала следующее:

[1604:2574][2013-12-04T11:49:51]i001: Burn v3.7.1224.0, Windows v6.2 (Build 9200: Service Pack 0), path: C:\Users\.....\MyProgram Setup.exe, cmdline: ''
[1604:2574][2013-12-04T11:49:51]i000: Setting string variable 'WixBundleLog' to value 'C:\Users\.....\MyProgram_20131204114951.log'
[1604:2574][2013-12-04T11:49:51]i000: Setting string variable 'WixBundleOriginalSource' to value 'C:\Users\.....\MyProgram Setup.exe'
[1604:2574][2013-12-04T11:49:51]i000: Setting string variable 'WixBundleName' to value 'MyProgram'
[1604:2574][2013-12-04T11:49:51]i100: Detect begin, 2 packages
[1604:2574][2013-12-04T11:49:51]i000: Setting string variable 'vcredist_x86' to value '1'
[1604:2574][2013-12-04T11:49:51]i000: Setting string variable 'vcredist_x64' to value '1'
[1604:2574][2013-12-04T11:49:51]i052: Condition 'vcredist_x86 AND (vcredist_x86 >= 1)' evaluates to true.
[1604:2574][2013-12-04T11:49:51]i101: Detected package: vcredist_x86, state: Present, cached: None
[1604:2574][2013-12-04T11:49:51]i101: Detected package: MyProgram, state: Absent, cached: None
[1604:2574][2013-12-04T11:49:51]i199: Detect complete, result: 0x0
[1604:2574][2013-12-04T11:49:53]i200: Plan begin, 2 packages, action: Install
[1604:2574][2013-12-04T11:49:53]w321: Skipping dependency registration on package with no dependency providers: vcredist_x86
[1604:2574][2013-12-04T11:49:53]i000: Setting string variable 'WixBundleRollbackLog_MyProgram' to value 'C:\Users\.....\MyProgram_20131204114951_0_MyProgram_rollback.log'
[1604:2574][2013-12-04T11:49:53]i000: Setting string variable 'WixBundleLog_MyProgram' to value 'C:\Users\.....\MyProgram_20131204114951_0_MyProgram.log'
[1604:2574][2013-12-04T11:49:53]i201: Planned package: vcredist_x86, state: Present, default requested: Present, ba requested: Present, execute: None, rollback: None, cache: No, uncache: No, dependency: None
[1604:2574][2013-12-04T11:49:53]i201: Planned package: MyProgram, state: Absent, default requested: Present, ba requested: Present, execute: Install, rollback: Uninstall, cache: Yes, uncache: No, dependency: Register
[1604:2574][2013-12-04T11:49:53]i299: Plan complete, result: 0x0
[1604:2574][2013-12-04T11:49:53]i300: Apply begin
[1FF8:10F8][2013-12-04T11:49:58]i360: Creating a system restore point.
[1FF8:10F8][2013-12-04T11:49:59]i361: Created a system restore point.
[1FF8:10F8][2013-12-04T11:50:00]i000: Caching bundle from: 'C:\Users\.....\{6ab8eece-89c6-4417-905f-6d9c5136519d}\.be\MyProgram Setup.exe' to: 'C:\ProgramData\Package Cache\{6ab8eece-89c6-4417-905f-6d9c5136519d}\MyProgram Setup.exe'
[1FF8:10F8][2013-12-04T11:50:00]i320: Registering bundle dependency provider: {6ab8eece-89c6-4417-905f-6d9c5136519d}, version: 2.0.0.0
[1604:2FB4][2013-12-04T11:50:00]i336: Acquiring container: WixAttachedContainer, copy from: C:\Users\.....\MyProgram Setup.exe
[1604:2FB4][2013-12-04T11:50:00]i000: Setting string variable 'WixBundleLastUsedSource' to value 'C:\Users\.....'
[1604:24F8][2013-12-04T11:50:00]e000: Error 0x80004005: Failed to extract all files from container.
[1604:2FB4][2013-12-04T11:50:00]e000: Error 0x80004005: Failed to wait for operation complete.
[1604:2FB4][2013-12-04T11:50:00]e000: Error 0x80004005: Failed to open container.
[1604:2FB4][2013-12-04T11:50:00]e000: Error 0x80004005: Failed to open container: WixAttachedContainer.
[1604:2FB4][2013-12-04T11:50:00]e312: Failed to extract payloads from container: WixAttachedContainer to working path: C:\Users\.....\{6ab8eece-89c6-4417-905f-6d9c5136519d}\C7C1FB4E513C19E0F5E8F6856FF2ACC4D7D143A2, error: 0x80004005.
[1604:2574][2013-12-04T11:50:00]e000: Error 0x80004005: Failed while caching, aborting execution.
[1FF8:10F8][2013-12-04T11:50:00]i330: Removed bundle dependency provider: {6ab8eece-89c6-4417-905f-6d9c5136519d}
[1FF8:10F8][2013-12-04T11:50:00]i352: Removing cached bundle: {6ab8eece-89c6-4417-905f-6d9c5136519d}, from path: C:\ProgramData\Package Cache\{6ab8eece-89c6-4417-905f-6d9c5136519d}\
[1604:2574][2013-12-04T11:50:00]i399: Apply complete, result: 0x80004005, restart: None, ba requested restart:  No

Затем я нашел еще одну альтернативу подписанию exe, добавив следующее в конец файла .wixproj:

  <Target Name="SignBundleEngine">
    <Exec Command="&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\signtool.exe&quot; sign /f &quot;$(ProjectDir)\sigFile.pfx&quot; /p sigKey /d &quot;My Program&quot; /t http://timestamp.verisign.com/scripts/timstamp.dll &quot;@(SignBundleEngine)&quot;" />
  </Target>
  <Target Name="SignBundle">
    <Exec Command="&quot;C:\Program Files (x86)\Microsoft SDKs\Windows\v7.0A\bin\signtool.exe&quot; sign /f &quot;$(ProjectDir)\sigFile.pfx&quot; /p sigKey /d &quot;My Program&quot; /t http://timestamp.verisign.com/scripts/timstamp.dll &quot;@(SignBundle)&quot;" />
  </Target>
  <PropertyGroup>
    <PostBuildEvent>"C:\Program Files (x86)\Microsoft SDKs\Windows\v7.1A\Bin\signtool.exe"  sign  /f "$(ProjectDir)\sigFile.pfx" /p sigKey /d "My Program" /t http://timestamp.verisign.com/scripts/timstamp.dll /v "MyProgram Setup.exe"</PostBuildEvent>
  </PropertyGroup>

Используя этот метод, установочный файл выполняет и устанавливает все правильно, но не идентифицирует издателя при запросе повышенного разрешения на установку, он говорит "Publisher: Unknown".

Кто-нибудь знает, как заставить цифровое подписывание работать над этим загрузчиком?

Вот мои файлы Bundle.wxs и vcredist.wxs:

Bundle.wxs

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">


  <Bundle Name="My Program"
          Version="2.0.0"
          Manufacturer="My Company"
          UpgradeCode="PUT-GUID-HERE"
          HelpUrl="http://www.mycompany.com"
          AboutUrl="http://www.mycompany.com"
          HelpTelephone="888 888 8888"
          IconSourceFile="Resources\program.ico">

    <BootstrapperApplicationRef Id="WixStandardBootstrapperApplication.HyperlinkLicense">
      <Payload SourceFile="Resources\Bootstrapper Screen.png" />
    </BootstrapperApplicationRef>

    <WixVariable Id="WixStdbaLicenseUrl" Value=""/>

    <WixVariable Id="WixStdbaThemeXml" Value="Resources\CustomHyperlinkTheme.xml"/>
    <WixVariable Id="WixStdbaThemeWxl" Value="Resources\CustomHyperlinkTheme.wxl"/>

    <Chain>

      <!-- Define the list of chained packages. -->
      <PackageGroupRef Id="vcredist"/>
      <MsiPackage Id="MyProgram"
                  SourceFile="$(var.MyProgramSetup.TargetPath)"
                  ForcePerMachine="yes" />
    </Chain>
  </Bundle>
</Wix>

vcredist.wxs

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi"
     xmlns:util="http://schemas.microsoft.com/wix/UtilExtension">
  <Fragment>
    <util:RegistrySearch Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\10.0\VC\VCRedist\x86" Value="Installed" Variable="vcredist_x86" />
    <util:RegistrySearch Root="HKLM" Key="SOFTWARE\Microsoft\VisualStudio\10.0\VC\VCRedist\x64" Value="Installed" Variable="vcredist_x64" />
    <PackageGroup Id="vcredist">
      <ExePackage Id="vcredist_x86"
        Cache="no"
        Compressed="yes"
        PerMachine="yes"
        Permanent="yes"
        Vital="yes"
        Name="vcredist_x86.exe"
        SourceFile="vcredist3.5_x86.exe"
        InstallCommand="/q"
        DetectCondition="vcredist_x86 AND (vcredist_x86 &gt;= 1)">
      </ExePackage>
    </PackageGroup>
  </Fragment>
</Wix>

Ответ 1

  <Target Name="UsesFrameworkSdk">
    <GetFrameworkSdkPath>
      <Output TaskParameter="Path" PropertyName="FrameworkSdkPath" />
    </GetFrameworkSdkPath>
    <PropertyGroup>
      <Win8SDK>$(registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\[email protected])</Win8SDK>
    </PropertyGroup>    
  </Target>

  <Target Name="UsesSignTool" DependsOnTargets="UsesFrameworkSdk">
    <PropertyGroup>
      <SignToolPath Condition="('@(SignToolPath)'=='') and Exists('$(FrameworkSdkPath)bin\signtool.exe')">$(FrameworkSdkPath)bin\signtool.exe</SignToolPath>
      <SignToolPath Condition="('@(SignToolPath)'=='') and Exists('$(Win8SDK)\bin\x86\signtool.exe')">$(Win8SDK)\bin\x86\signtool.exe</SignToolPath>
    </PropertyGroup>
  </Target>

  <Target Name="SignBundleEngine" DependsOnTargets="UsesSignTool">
    <Exec Command="&quot;$(SignToolPath)&quot; sign /d &quot;App Setup&quot; /t http://timestamp.digicert.com /a &quot;@(SignBundleEngine)&quot;" />
  </Target>

  <Target Name="SignBundle" DependsOnTargets="UsesSignTool">
    <Exec Command="&quot;$(SignToolPath)&quot; sign /d &quot;App Setup&quot; /t http://timestamp.digicert.com /a &quot;@(SignBundle)&quot;" />
  </Target>

Это хорошо работает для меня. Либо вы делаете это во время сборки, либо вам нужно использовать знаки отличия.
Например: http://wixtoolset.org/documentation/manual/v3/overview/insignia.html

insignia -ib bundle.exe -o engine.exe
... sign engine.exe
insignia -ab engine.exe bundle.exe -o bundle.exe
... sign bundle.exe

Ответ 2

Для меня использование встроенного инструмента WiX insignia является наиболее простым. Здесь шаги, которые я сделал, чтобы сделать кодовым знаком WiX MSI и установщик начальной загрузки:
(шаги 1 и 2 только что настроены, чтобы сделать чтение 3 и 4 легко и многократно повторяемым и обновляемым). Шаги 3 и 4 являются фактическим подписанием)

  • Настройте signtool как пакетный файл в моем PATH, чтобы я мог его вызвать и легко его изменить. Я запускаю Windows 10, поэтому мой "signtool.bat" выглядит следующим образом:
    "c:\Program Files (x86)\Windows Kits\10\bin\x64\signtool.exe" %*
  • Настройте insignia как пакетный файл в моей PATH, чтобы вы могли изменить его с помощью новых сборок WiX по мере их появления. Мой "insignia.bat" выглядит следующим образом:
    "C:\Program Files (x86)\WiX Toolset v3.10\bin\insignia.exe" %*
  • Подпишите мой MSI в событии после сборки (проект MSI → Свойства → События сборки), вызвав это:
    signtool sign /f "c:\certificates\mycert.pfx" /p cert-password /d "Your Installer Label" /t http://timestamp.verisign.com/scripts/timstamp.dll /v $(TargetFileName)
  • Подпишите мой пакет в событии post-build для проекта начальной загрузки следующим образом:

    CALL insignia -ib "$(TargetFileName)" -o engine.exe
    CALL signtool sign /f "c:\certificates\mycert.pfx" /p cert-password /d "Installer Name" /t http://timestamp.verisign.com/scripts/timstamp.dll /v engine.exe
    CALL insignia -ab engine.exe "$(TargetFileName)" -o "$(TargetFileName)"
    CALL signtool sign /f "c:\certificates\mycert.pfx" /p cert-password /d "Installer Name" /t http://timestamp.verisign.com/scripts/timstamp.dll /v "$(TargetFileName)"


Дальнейшие заметки и мысли:

  • Я также подписал приложение (я думаю), просто выполнив Project Properties -> Signing и включив манифесты click-once, выбрав сертификат и проверку опции Sign the assembly.

  • Указание CALL необходимо в событиях после сборки при вызове командный файл или только первый вызываемый.

Ответ 3

Далее ответ @jchoover, у вас есть 3 варианта при подписании пакетов:

  • Соберите пакет без подписи, затем подпишите его позже. Однако вам также необходимо подписать исполняемый файл движка, встроенный в комплект. Как говорит @jchoover, вы можете использовать insignia, чтобы обойти это путем извлечения движка в файл. Затем вы можете подписать файл, используя обычный процесс (например, с помощью signtool.exe), а затем импортировать его обратно в пакет.

  • Добавьте цели SignBundle и SignBundleEngine к своим проектам. Вы можете сделать это, открыв их в текстовом редакторе и отредактировав основной код MSBuild. Ответ @jchoover описывает, как вы можете это сделать.

  • Создайте файл .targets с целями SignBundle и SignBundleEngine и передайте путь с помощью свойства CustomAfterWixTargets:

    msbuild your.sln/p:CustomAfterWixTargets=customafterwix.targets/p:SignOutput=true

Ответ 4

Обновление для VS2019, и на основе ответа @jchoover, вот что я получил работать.

Это использует некоторые MSBuild функции собственности работу по @webjprgm здесь, что делает поиск signtool.exe более общие по версии пакета Windows. Как упомянуто @karfus в комментарии выше, добавление раздела SignOutput - это заклинание, с которого все начинается.

Это идет в конце вашего файла bootstrap.wixproj, перед закрывающим тегом /Project.

  <!-- SignOutput must be present in some PropertyGroup to trigger signing. -->
  <PropertyGroup> 
    <SignOutput>true</SignOutput>
  </PropertyGroup>

  <!-- Find Windows Kit path and then SignTool path for the post-build event -->
  <Target Name="FindSignTool">
      <PropertyGroup>
        <WindowsKitsRoot>$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots', 'KitsRoot10', null, RegistryView.Registry32, RegistryView.Default))</WindowsKitsRoot>
        <WindowsKitsRoot Condition="'$(WindowsKitsRoot)' == ''">$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots', 'KitsRoot81', null, RegistryView.Registry32, RegistryView.Default))</WindowsKitsRoot>
        <WindowsKitsRoot Condition="'$(WindowsKitsRoot)' == ''">$([MSBuild]::GetRegistryValueFromView('HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows Kits\Installed Roots', 'KitsRoot', null, RegistryView.Registry32, RegistryView.Default))</WindowsKitsRoot>
        <SignToolPath Condition="'$(SignToolPath)' == '' And '$(Platform)' == 'AnyCPU' and Exists('$(WindowsKitsRoot)bin\x64\signtool.exe')">$(WindowsKitsRoot)bin\x64\</SignToolPath>
        <SignToolPath Condition="'$(SignToolPath)' == '' And Exists('$(WindowsKitsRoot)bin\$(Platform)\signtool.exe')">$(WindowsKitsRoot)bin\$(Platform)\</SignToolPath>
        <SignToolPathBin Condition="'$(SignToolPath)' == ''">$([System.IO.Directory]::GetDirectories('$(WindowsKitsRoot)bin',"10.0.*"))</SignToolPathBin>
        <SignToolPathLen Condition="'$(SignToolPathBin)' != ''">$(SignToolPathBin.Split(';').Length)</SignToolPathLen>
        <SignToolPathIndex Condition="'$(SignToolPathLen)' != ''">$([MSBuild]::Add(-1, $(SignToolPathLen)))</SignToolPathIndex>
        <SignToolPathBase Condition="'$(SignToolPathIndex)' != ''">$(SignToolPathBin.Split(';').GetValue($(SignToolPathIndex)))\</SignToolPathBase>
        <SignToolPath Condition="'$(SignToolPath)' == '' And '$(SignToolPathBase)' != '' And '$(Platform)' == 'AnyCPU'">$(SignToolPathBase)x64\</SignToolPath>
        <SignToolPath Condition="'$(SignToolPath)' == '' And '$(SignToolPathBase)' != ''">$(SignToolPathBase)$(Platform)\</SignToolPath>
      </PropertyGroup>
  </Target>

  <!-- Sign the bundle engine -->
  <Target Name="SignBundleEngine" DependsOnTargets="FindSignTool">
    <Exec Command="&quot;$(SignToolPath)signtool.exe&quot; sign /d &quot;MyApp Setup&quot; /fd SHA256 /td SHA256 /a /f &quot;MyApp Code Certificate.pfx&quot; /p CertPassword /tr http://timestamp.digicert.com /a &quot;@(SignBundleEngine)&quot;" />
  </Target>

  <!-- Sign the final bundle -->
  <Target Name="SignBundle" DependsOnTargets="FindSignTool">
    <Exec Command="&quot;$(SignToolPath)signtool.exe&quot; sign /d &quot;MyApp Setup&quot;  /fd SHA256 /td SHA256 /a /f &quot;MyApp Code Certificate.pfx&quot; /p CertPassword /tr http://timestamp.digicert.com /a &quot;@(SignBundle)&quot;" />
  </Target>