mansellan / clickonce

ClickOnce packager
Other
26 stars 7 forks source link

Azure devops task deleting secure file is causing problems with launcher signing #64

Open daniel-p-snowden opened 8 months ago

daniel-p-snowden commented 8 months ago

I've been using the clickonce packager tool and Azure Devops task template for a few months now. So far it's been an absolute lifesaver when we were struggling to move from publishing our application (directly) in Visual Studio to CI/CD with Azure.

The problem we're currently experiencing is as part of a proof of concept to move from .NET Framework 4.8 to .NET6/7. In theory, we should be able to use a launcher to deploy a .NET 6/7 application but we have encountered a security related issue. Our environment requires all exes to be signed. The issue is that although we have signed our application (and similarly sign the manifests for ClickOnce), the launcher is not signed and is therefore blocked.

We had planned to sign the launcher after the package is generated but the the clickonce packager deletes the certificate (downloaded as a secure file) after the package is generated.

Our packaging task is set up as follows (for reference) - task: clickonce@1 displayName: Create ClickOnce Package inputs: source: '$(ClickOnceSource)' target: '$(ClickOnceTarget)' product: '$(Product)' version: '$(GitVersion.AssemblySemVer)' publisher: '$(clickOnce.Publisher)' launchMode: 'start' deploymentUrl: '$(DeploymentUrl)' targetFramework: 'net48' entryPoint: '$(WindowsAssemblytoSign).Launcher' iconFile: '$(IconAndPathForClickOnce)' signingMode: 'file' certificate: '$(innitechCertificate.secureFilePath)' certificatePassword: '$(innitechCertificate.password)' timestampUrl: '$(innitechCertificate.TimestampUrl)' useLauncher: 'true' verbosity: 'verbose' Most of the values are set by pipeline variables, but are included to show which options we are using for packaging.

So because secure files can't be re-downloaded we appear to have no way to sign the launcher. Possible solutions could be:

  1. Make deleting the secure file optional, or remove this entirely as the file is deleted automatically when the pipeline job completes
  2. Integrate signing of the generated launcher as part of the task
mansellan commented 6 months ago

Hi, thanks for using my extension. Sorry for not responding sooner

As you probably realized by now, this project is not that active any more. I figured it was near enough to being feature-complete that I didn't have to check in very often.

I'm happy to look into this, in fact I'm surprised I didn't get it to sign the launcher by default, or at least offer an option for it. Option 2 looks good to me.

In the meantime, as a workaround, did you try the "Code Signing Task"? I've used that in many of my MSIX pipelines, and it works great.

daniel-p-snowden commented 6 months ago

Thanks for getting back to me.

We haven't tried the code signing task, we're still using signtool manually. But we do currently have a workaround in place. The workaround is that the application is effectively set up for clickonce in the project (through the "true" attribute), which does create a launcher exe that clickonce can use. Our build pipeline then copies the output, excluding the manifests, to the staging folder for packaging.

Not the most elegant solution, so if you can integrate signing of the generated launcher that would be perfect.

If you do implement that then I'd suggest allowing the option of files and installed certificates. Reason being, we currently use a pfx file but this is going to need replacing at some point due to the requirement to store private keys to code signing certs in a Hardware Security Module. As a longer term solution we're looking at "Software Trust Manager", which should effectively "trick" the agent in to thinking that the certificate is installed locally.

In the meantime I'll have a look at the Code Signing task. If nothing else, it should at least make our code signing tasks neater compared with calling SignTool.exe from powershell