Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Signing a ClickOnce manifest through TFS Build 2008?

I'm having a problem figuring out how to "Sign the ClickOnce manifests" of my application from TFS Build.

I've configured my signing page in VS 2010 by checking the "Sign the ClickOnce manifests" checkbox and choosing our code-signing key from a file, as pictured in the below screenshot:

Signing page in VS 2010

Now, when I publish the application from VS 2010, the manifest appears to be signed successfully:

security warning showing good certificate

However, when I try to build the application from TFS Build, it doesn't appear to attempt to sign the manifest. In fact, there's not even an error message indicating that something failed.

I tried to set up the TFSBuild.proj file so that my build server is aware of the certificate and that I wish to sign my manifests, but I wasn't sure how to do that.

I've tried the following:

<CustomPropertiesForBuild>SignManifests=true;ManifestCertificateThumbprint=<thumbprint goes here></CustomPropertiesForBuild>

But it doesn't seem to make any difference. (No errors are generated, either).

Note: I am not interested in strong naming my assemblies; just signing my code.

Does anyone know how to do this? Has anyone successfully deployed ClickOnce apps from TFS Build?

like image 564
Pandincus Avatar asked May 19 '11 13:05

Pandincus


1 Answers

So far, the only way I have been able to sign my code via TFSBuild is to launch the command-line code signing tool. This basically involves three steps:

  1. Import the certificate onto the build machine, while logged in as whatever TFSService account you use to run TFSBuild. Once you've got the certificate imported, you'll need to go into Cert Manager to get it's thumbprint (I think it's called the "hash" in the cert manager UI).

  2. Add a Target to your .csproj/.wixproj/.whateverproj that locates signtool.exe and runs it:

    <Target Name="SignOutput">
      <PropertyGroup>
        <WindowsSdkDir>$(Registry:HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Microsoft SDKs\Windows\@CurrentInstallFolder)</WindowsSdkDir>
        <WindowsSdkDir Condition="'$(WindowsSdkDir)' != '' and !HasTrailingSlash('$(WindowsSdkDir)')">$(WindowsSdkDir)\</WindowsSdkDir>
        <SignToolPath>$(WindowsSdkDir)bin\signtool.exe</SignToolPath>
        <Hash>...</Hash>
        <TsUrl>http://timestamp.verisign.com/scripts/timstamp.dll</TsUrl>
      </PropertyGroup>
      <ItemGroup>
        <SignableFiles Include="$(TargetDir)\Setup.msi" />
        <SignableFiles Include="$(TargetDir)\Data.cab" />
      </ItemGroup>
      <ResolveKeySource CertificateThumbprint="$(Hash)">
          <Output TaskParameter="ResolvedThumbprint" PropertyName="LocatedThumbprint"/>
      </ResolveKeySource>
      <Exec Condition="'$(LocatedThumbprint)' != '' and Exists('$(SignToolPath)')" ContinueOnError="true" Command="'$(SignToolPath)' sign /q /sha1 $(LocatedThumbprint) /t $(TsUrl) '%(SignableFiles.Identity)'" />
    </Target>
    
  3. Call your new target at the appropriate time; we only sign release builds, so we do this:

    <Target Name="AfterBuild">
      <CallTarget Targets="SignOutput" Condition="'$(ConfigurationName)' == 'Release'" />
    </Target>
    

This method also works on the developer machines, assuming they have the proper SDK tools installed. If they don't it will just skip the signing step, which for us has worked fine.

like image 84
Michael Edenfield Avatar answered Nov 15 '22 08:11

Michael Edenfield