Migrate ClickOnce certificate from Sha1 to SHA256 and run on .NET 4.0 client machines

1.3k views Asked by At

After discovering the signing issue with .NET 4.5 vs .NET 4.0 when upgrading from an SHA1 to an SHA256 signed certificated, I decided to re-implement our ClickOnce build process to follow a more standard approach so I could make use of VS2013 Update 3. However it didn't seem to have an effect. I know that the manifest is being built and is working correctly as it installs fine on any machine running .NET 4.5, however .NET 4.0 apps still fail.

I use CruiseControl.NET to manage our builds To do run the builds I use one of these two tasks, but get the same result. A .application file which works on .NET 4.5 but not 4.0 with the errors mentioned in the article For Example:

`<devenv>
    <solutionfile>$(SolutionFile)</solutionfile>
    <configuration>$(Config)</configuration>
    <buildtype>Build</buildtype>
    <executable>C:\Program Files (x86)\Microsoft Visual Studio 12.0\Common7\IDE\devenv.com</executable>
    <version>VS2013</version>
</devenv>`

Or with MSBuild:

 <msbuild>
   <executable>C:\Program Files (x86)\MSBuild\12.0\Bin\MSBuild.exe</executable>
   <workingDirectory>$(WorkingDirectory)</workingDirectory>
   <projectFile>$(SolutionPath)</projectFile>
   <buildArgs>
     /p:Configuration=$(Config) /p:BuildFolder="$(BuildFolder)" 
   </buildArgs>
   <targets>clean;publish</targets>
 </msbuild>

i've tried setting the toolsversion in the msbuild args, as well as a number of other approaches, but nothing seems to work and forces my end user to uninstall and re-install which I'm attempting to avoid.

I've been battling with ClickOnce for the past two weeks in order to try and prevent any issues with migrating to a new certificate, but I can't seem to get this last piece working right. Any guidance here at all would be greatly appreciated.

1

There are 1 answers

0
SomeInternetGuy On BEST ANSWER

The solution to this was not clear and poorly documented but after a lot of hacking through code and msbuild files I found the solution.

This answer is likely incomplete with regard to the specific issues I ran into, however I'll try to cover the basis for anyone else who runs into this problem.

First, for the build target we need to make a small change, we need to set the tool version of MSBuild to the latest and greatest so that we can utilize a bug fix for the specific issue of ClickOnce not working with an SHA256 certificate when run on a computer with only .NET 4.0 installed. We do this by installing Visual Studio 2013 or greater on the build machine so we have an up to date version of MSbuild to use. Note that the executable path here has "MSBuild\12.0" in it. We will need atleast version 12 for this to work.

<msbuild>
  <executable>C:\Program Files (x86)\MSBuild\12.0\Bin\MSBuild.exe</executable>
  <workingDirectory>$(WorkingDirectory)</workingDirectory>
  <projectFile>$(SolutionPath)</projectFile>
  <buildArgs>
    /tv:12.0 /p:Configuration=$(Config) /p:BuildFolder="$(BuildFolder)" 
  </buildArgs>
  <targets>clean;publish</targets>
</msbuild> 

After making this change I ran into a number of other problems created by the legacy build configuration that was present. In order to use this MSBuild I had to pull out ClickOnce build back to the basic format you would see in any ClickOnce sample. This was good for the future, but created many problems.

One specific problem which was hard to resolve was that the AssemblyIdentity was now set to AssemblyName.application, Where as I had a custom value, MyCustomIdentity.app

It took me a while to verify that in fact the identity was derived from the Projects AssemblyName value.

I found this out by inspecting the Microsoft.Common.targets file, looking through the default Build target I found that there is a tag

<_DeploymentDeployManifestIdentity>$(AssemblyName)</_DeploymentDeployManifestIdentity>

Since this is still just MSBuild XML, I realized I could copy this out and push it into my project file to set my own, however where you do this in your file matters.

You will have to put this in AFTER the imports for targets which could override this. I played it safe by adding it as the last element under Project.

<_DeploymentDeployManifestIdentity> MyCustomIdentity.app </_DeploymentDeployManifestIdentity>