Click here to Skip to main content
13,764,506 members
Click here to Skip to main content
Add your own
alternative version

Stats

8.1K views
5 bookmarked
Posted 14 Jan 2018
Licenced CPOL

How to Sign ClickOnce Deployment if ClickOnce Code Signing Function in Visual Studio Doesn't Work

, 15 Jan 2018
Rate this:
Please Sign up or sign in to vote.
How to properly sign ClickOnce deployment in a way that actually works

Introduction

Recently, I was developing a WPF desktop application. This application was to be available for download from a website so we needed an installer to install this app on customer computers. The app and the installer had to be code signed to avoid being blocked by SmartScreen and antivirus programs.

I decided to use ClickOnce technology because it seemed like the easiest approach to generate installer and it provides automatic updates. Unfortunately, it soon turned out that code signing a ClickOnce deployment is quite a difficult task. There are some tips on the Internet about how to sign a ClickOnce deployment, but they do not cover the whole subject so I decided to write how I solved this problem by myself.

Background

The ClickOnce deployment consists of four parts:

  1. The application files
  2. Application manifest
  3. Deployment manifest
  4. Boostrapper file (setup.exe)

It's important that these four elements have to be signed separately. Many developers are only signing application files or only manifests. It can lead to deployment errors and the SmartScreen filter will still block the improperly signed application.

Signing ClickOnce Deployment in Visual Studio

First of all, do not use this:

These options should theoretically sign your ClickOnce manifest automatically but they don't allow you to specify command line arguments for signtool so they just don't work with some electronic signatures. What you have to do is to manually edit your project file and add some deployment targets.

1. Sign the application file

Right click your project and select Unload project. Then right click on the unloaded project and select "Edit <projectname>.csproj". The code editor appears.

Scroll to the bottom and add a new target just before the last closing </Project> tag:

<Target Name="AfterCompile" Condition="
'$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

  <Exec Command="&quot;C:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe&quot;
  sign /n &quot;InsertNameHere&quot; /t http://yourtimestampuri /fd sha1
  /v &quot;$(ProjectDir)obj\$(ConfigurationName)\$(TargetFileName)&quot;" />

</Target>

Of course, you have to replace "C:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe" with the correct signtool path in your OS and provide valid command line parameters for signtool. Usually electronic signature resellers provide tutorials on how to properly use signtool.

The above code snippet signs the application file. Now you have to sign two manifests and the boostrapper file.

2. Sign the application manifest

Add a second target to .csproj file:
  <Target Name="SignManifest" AfterTargets="_DeploymentSignClickOnceDeployment" 

   Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">

</Target>

Now we will add four commands to this target tag. First of all, we have to sign the application manifest:

<Exec Command="&quot;C:\Program Files 
(x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools\mage.exe&quot; 
-Sign &quot;$(_DeploymentApplicationDir)$(_DeploymentTargetApplicationManifestFileName)&quot; 
-CertHash INSERTVALIDHASHHERE -TimeStampUri http://yourtimestampuri" />

Mage.exe is a tool for editing and signing ClickOnce manifests. You will have to find it on your system and provide a valid path to that file.

3. Update deployment manifest to reference the signed version of application manifest

The above command signs the application manifest. You now have a signed application manifest and unsigned deployment manifest. There's no use to sign the deployment manifest now because it still references the unsigned version of the application manifest. You have to update the generated deployment manifest to reference the signed version of the application manifest:

<Exec Command="&quot;C:\Program Files 
(x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools\mage.exe&quot; 
-Update &quot;$(PublishDir)$(TargetDeployManifestFileName)&quot; 
-AppManifest &quot;$(_DeploymentApplicationDir)$(_DeploymentTargetApplicationManifestFileName)&quot;" />

4. Sign the deployment manifest

The deployment manifest now references the correct application manifest so we can sign it now:

<Exec Command="&quot;C:\Program Files 
(x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools\mage.exe&quot; 
-Sign &quot;$(PublishDir)$(TargetDeployManifestFileName)&quot; 
-CertHash INSERTVALIDHASHHERE -TimeStampUri http://yourtimestampuri" />

5. Sign the bootstrapper file

We have both manifests signed. Now we just have to sign the setup.exe file:

<Exec Command="&quot;C:\Program Files 
(x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe&quot; 
sign /n &quot;CertificateName&quot; /t http://yourtimestampuri /fd sha1 
/v &quot;$(PublishDir)\setup.exe&quot;" />

That's all. The all four elements of the ClickOnce deployment are now properly signed.

Summary

This is the full code that you have to insert to .csproj file:

  <Target Name="AfterCompile" Condition=" 
'$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <Exec Command="&quot;C:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe&quot; 
     sign /n &quot;InsertNameHere&quot; /t http://yourtimestampuri /fd sha1 
     /v &quot;$(ProjectDir)obj\$(ConfigurationName)\$(TargetFileName)&quot;" />
  </Target>

  <Target Name="SignManifest" AfterTargets="_DeploymentSignClickOnceDeployment" 

   Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <Exec Command="&quot;C:\Program Files 
    (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools\mage.exe&quot; 
    -Sign &quot;$(_DeploymentApplicationDir)$(_DeploymentTargetApplicationManifestFileName)&quot; 
    -CertHash INSERTVALIDHASHHERE -TimeStampUri http://yourtimestampuri" />
    <Exec Command="&quot;C:\Program Files 
    (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools\mage.exe&quot; 
    -Update &quot;$(PublishDir)$(TargetDeployManifestFileName)&quot; 
    -AppManifest &quot;$(_DeploymentApplicationDir)$
    (_DeploymentTargetApplicationManifestFileName)&quot;" />
    <Exec Command="&quot;C:\Program Files 
    (x86)\Microsoft SDKs\Windows\v10.0A\bin\NETFX 4.6.2 Tools\mage.exe&quot; 
    -Sign &quot;$(PublishDir)$(TargetDeployManifestFileName)&quot; 
    -CertHash INSERTVALIDHASHHERE -TimeStampUri http://yourtimestampuri" />
    <Exec Command="&quot;C:\Program Files 
     (x86)\Microsoft SDKs\ClickOnce\SignTool\signtool.exe&quot; 
     sign /n &quot;CertificateName&quot; /t http://yourtimestampuri /fd sha1 
     /v &quot;$(PublishDir)\setup.exe&quot;" />
  </Target>

Points of Interest

Electronic signature resellers offer you two types of code signing certificates: standard code signing and extended validation code signing. The second type instantly removes SmartScreen warning when customers try to install your application. The first type of certificate removes SmartScreen after some time when your application gathers reputation points. In my opinion, Extended Validation certificates are not worth buying. We use Standard certificate and the SmartScreen filter message disappeared after about two weeks since the product release. We haven't seen a SmartScreen message since then.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Ajcek84
Poland Poland
I graduated from Adam Mickiewicz University in Poznań where I completed a MA degree in computer science (MA thesis: Analysis of Sound of Viola da Gamba and Human Voice and an Attempt of Comparison of Their Timbres Using Various Techniques of Digital Signal Analysis) and a bachelor degree in musicology (BA thesis: Continuity and Transitions in European Music Theory Illustrated by the Example of 3rd part of Zarlino's Institutioni Harmoniche and Bernhard's Tractatus Compositionis Augmentatus). I also graduated from a solo singing class in Fryderyk Chopin Musical School in Poznań. I'm a self-taught composer and a member of informal international group Vox Saeculorum, gathering composers, which common goal is to revive the old (mainly baroque) styles and composing traditions in contemporary written music. I'm the annual participant of International Summer School of Early Music in Lidzbark Warmiński.

You may also be interested in...

Pro
Pro

Comments and Discussions

 
QuestionUpgrade from unsigned to signed application Pin
Narinder Mittal21-Jun-18 20:37
memberNarinder Mittal21-Jun-18 20:37 
AnswerRe: Upgrade from unsigned to signed application Pin
Ajcek8415-Jul-18 7:59
memberAjcek8415-Jul-18 7:59 
QuestionThanks Pin
tixik3-Jun-18 10:49
membertixik3-Jun-18 10:49 
QuestionUltimate guide??? Pin
Graeme_Grant14-Jan-18 20:24
mvpGraeme_Grant14-Jan-18 20:24 
AnswerRe: Ultimate guide??? Pin
Ajcek8414-Jan-18 22:53
memberAjcek8414-Jan-18 22:53 
GeneralRe: Ultimate guide??? Pin
Graeme_Grant14-Jan-18 23:12
mvpGraeme_Grant14-Jan-18 23:12 
GeneralRe: Ultimate guide??? Pin
Ajcek8414-Jan-18 23:24
memberAjcek8414-Jan-18 23:24 
GeneralRe: Ultimate guide??? Pin
Graeme_Grant14-Jan-18 23:35
mvpGraeme_Grant14-Jan-18 23:35 
GeneralRe: Ultimate guide??? Pin
Ajcek8415-Jan-18 0:44
memberAjcek8415-Jan-18 0:44 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web01-2016 | 2.8.181113.4 | Last Updated 15 Jan 2018
Article Copyright 2018 by Ajcek84
Everything else Copyright © CodeProject, 1999-2018
Layout: fixed | fluid