.netclickoncemanifestauthenticode

.NET ClickOnce Signing results in "Unknown Publisher"


I am working on deploying a ClickOnce Application build on .NET 4.5 Here are the facts:

  1. I have a valid Comodo Authenticode Certificate
  2. The certificate is installed in my local cert store
  3. The project properties for "Signing" tab show that the certificate should be used for signing the manifest (I'm not even yet trying to sign the Assemblies for .NET)
  4. The proper timestamp server URL is entered for comodo
  5. On the Publish tab, the settings are very typical:
  6. Publish to a UNC path
  7. Installation folder is a URL mapped to that path in IIS

However, no matter what I do, when I use the "Publish Now" button to actually publish the ClickOnce application, all of the file get published, but when I download the "Setup.exe", it ALWAYS says "Unknown Publisher".

Any ideas on what I'm doing wrong? I have been researching this for several weeks and I have read through enough to believe that I'm doing it "correctly", but I just must be missing some small checkbox or setting, or something of course.

Any help appreciated.

-- W.G.


Solution

  • As far as I know the "Unknown Publisher" keys off the code-signing, which Visual Studio doesn't provide an interface for. Oh, it does have signing interfaces, but only for manifest signing and strong-name assembly signing. This other question mentions the three signings, too.

    To get the "Unknown Publisher" replaced with your org name, you'll have to add a bit of XML to your .csproj or .vbproj file. Right before the closing </Project> tag, you'll need to call SignTool.exe, which I manually copied to my solution's main Bin folder (If you don't have it, it's part of the Windows SDK). Here's what mine looks like:

      <!-- This section is used for code-signing the application. This should not be confused with manifest signing or with strong-name assembly signing, which can both be done from the Visual Studio interface. -->
      <Target Name="SignOutput" AfterTargets="CoreCompile">
        <PropertyGroup>
          <TimestampServerUrl>http://timestamp.verisign.com/scripts/timstamp.dll</TimestampServerUrl>
          <ApplicationDescription>A.Franklin's Awesome App</ApplicationDescription>
          <SigningCertificateCriteria>/sha1 0c0ff5e29404b7d78q2517f487da0b1a0912c4da</SigningCertificateCriteria>
        </PropertyGroup>
        <ItemGroup>
          <SignableFiles Include="$(ProjectDir)obj\$(ConfigurationName)\$(TargetName)$(TargetExt)" />
        </ItemGroup>
        <Exec Command="&quot;$(ProjectDir)..\Bin\SignTool&quot; sign $(SigningCertificateCriteria) /d &quot;$(ApplicationDescription)&quot; /t &quot;$(TimestampServerUrl)&quot; &quot;%(SignableFiles.Identity)&quot;" />
      </Target>
    

    To get the hash code (the "0c0ff5..." above) for my certificate, which I already had installed on my machine, I did this:

    1. Ran certmgr.msc and opened Certificates – Current User > Personal > Certificates
    2. Double-clicked the certificate I wanted and clicked the Details tab
    3. Used Ctrl-C to copy the value for Thumbprint (which looked like "0c f0 f5..."), except for the first character. There’s an invisible character in this textbox that gets copied along with the first character, and it messes up your script later on. So manually type the first character (a "0" in this case), then paste the value from this dialog box. If you get the error, "Invalid SHA1 hash format: ?0c 0f f5..." in Visual Studio, that question mark means the invisible character is there.
    4. Manually type the first character, then paste the value from this dialog box. Delete all spaces, so that it looks like 0c0ff5..., and make the line look like the SigningCertificateCriteria code above.

    You could use SignTool.exe manually too, but for me this setup runs it transparently during each compile.