msbuild: `SignFile` task using dotnet cli tries to use `signtool.exe` from wrong location
Issue Description
Thanks to issue #6098, the SignFile
task is now enabled in dotnet msbuild
16.11.
However, it does not actually seem to work.
I was under the impression that SignFile
did the signing itself, using core framework functionality.; however, it turns out it wants to use signtool.exe
, but does not actually locate it correctly.
So when using SignFile
as part of dotnet build
, I get:
error MSB3482: An error occurred while signing: SignTool.exe was not found at path xxx\signtool.exe.
where xxx is the project directory. When building a solution it wants signtool.exe
to be present in every project’s directory separately.
MSBuild should be able to locate it properly; I had my own lookup in place before, using
<SignToolPath Condition=" '$(SignToolPath)' == '' and '$(WindowsSdkVerBinPath)' != '' and '$(PROCESSOR_ARCHITECTURE)' == 'AMD64' and Exists('$(WindowsSdkVerBinPath)x64\signtool.exe') ">$(WindowsSdkVerBinPath)x64\signtool.exe</SignToolPath>
<SignToolPath Condition=" '$(SignToolPath)' == '' and '$(WindowsSdkVerBinPath)' != '' and '$(PROCESSOR_ARCHITECTURE)' == 'AMD64' and Exists('$(WindowsSdkVerBinPath)x86\signtool.exe') ">$(WindowsSdkVerBinPath)x86\signtool.exe</SignToolPath>
<SignToolPath Condition=" '$(SignToolPath)' == '' and '$(WindowsSdkVerBinPath)' != '' and '$(PROCESSOR_ARCHITECTURE)' == 'x86' and Exists('$(WindowsSdkVerBinPath)x86\signtool.exe') ">$(WindowsSdkVerBinPath)x86\signtool.exe</SignToolPath>
and that would have led to using C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x64\signtool.exe
just fine.
Steps to Reproduce
- create a simple project:
dotnet new classlib -n CodeSigning cd CodeSigning
- generate a self-signed certificate
This will produce output like:New-SelfSignedCertificate -Type CodeSigningCert -Subject CN=CodeSigning -CertStoreLocation Cert:\CurrentUser\My
make a note of that thumbprint value; it’s needed in the next step.PSParentPath: Microsoft.PowerShell.Security\Certificate::CurrentUser\My Thumbprint Subject EnhancedKeyUsageList ---------- ------- -------------------- B77064C7175EF732F534B8D28C337CA2FB87E9D2 CN=CodeSigning Code Signing
- Set up code signing in the project by adding this target to CodeSigning.csproj:
making sure that the value of<Target Name="_SignAssemblies" AfterTargets="Compile" DependsOnTargets="CreateSatelliteAssemblies;$(RazorCompileDependsOn)"> <PropertyGroup> <SigningCertificate>B77064C7175EF732F534B8D28C337CA2FB87E9D2</SigningCertificate> </PropertyGroup> <ItemGroup> <_AssembliesToSign Include="$(IntermediateOutputPath)$(TargetFileName)" /> <_AssembliesToSign Include="@(IntermediateSatelliteAssembliesWithTargetPath)" /> <_AssembliesToSign Include="@(RazorIntermediateAssembly)" /> </ItemGroup> <Message Importance="high" Text="Signing assemblies: @(_AssembliesToSign)" /> <SignFile SigningTarget="%(_AssembliesToSign.Identity)" CertificateThumbprint="$(SigningCertificate)" /> </Target>
$(SigningCertificate)
is the thumbprint of the certificate you generated. - build using
msbuild
; this should succeed, with output including_SignAssemblies: Signing assemblies: obj\Debug\net5.0\CodeSigning.dll CopyFilesToOutputDirectory:
- build using
dotnet build -v:n
; this will fail with an error like_SignAssemblies: Signing assemblies: obj\Debug\net5.0\CodeSigning.dll 1>...\CodeSigning\CodeSigning.csproj(17,5): error MSB3482: An error occurred while signing: SignTool.exe was not found at path ...\CodeSigning\signtool.exe.
Expected Behavior
The SignFile
task works, signing the assemblies, when using either dotnet build
or msbuild
.
Actual Behavior
The SignFile
task works only when using msbuild
.
Analysis
The SignFile
task implementation does not seem to locate SignTool correctly when using dotnet build
.
(And in addition, I thought that it was doing the signing itself (which would potentially make it work on Linux as well, which would be very convenient for CI/CD scenarios), using corefx functionality, not using an external utility from a Windows Kit.)
Versions & Configurations
Tested using VS2019 16.11.2 and .NET SDK 5.0.400, i.e. MSBuild 16.11.0.36601 on x64 Windows.
I’m not sure how to set up a certificate on Linux (no New-SelfSignedCertificate
in pwsh
there), but that would only matter if SignFile
did the signing itself and not via SignTool.
About this issue
- Original URL
- State: open
- Created 3 years ago
- Comments: 18 (14 by maintainers)
@rainersigwald Thanks for the reply.
So is there a plan for making signed binaries a first-class concept in the .NET SDK? So this task was just all about ClickOnce. To me though, since all operating systems have signed binaries, in this day an age, and where the .NET SDK is and going in the future, it’d seem prudent to have a universal way of signing binaries with the SDK.
Outside of ClickOnce, Windows has just good old Authenticode, signed DLLs, EXEs, MSIs, etc. It seems like Linux also has signed ELF binaries. It’s odd that in 2023 we’re still having to hunt for a copy of signtool on our build machines, and it’s limited to just Windows.
It’d be amazing if this task could find new life as a generic cross-platform signing task. 😃
I suppose it would be nice to document the task better then. It is not described as “an internal task intended for signing click-once artefacts only. Requires either Visual Studio and/or a Windows 8.1 SDK to be installed”. Instead, it suggests it performs general authenticode signing, but then does not, and has additional dependencies that make sense for
msbuild.exe
but notdotnet msbuild
.It certainly feels like there is little to no support for Authenticode in a .NET context - if that’s the intent, fine.
@BenVillalobos It thought it worked in your case because it found the ClickOnce install by looking in the right registry key when run in 64-bit mode, which is apparently a fix in 17 but not 16.11.
It makes no sense to me to have to install an obsolete SDK to make this work. We’re signing all built assemblies, not just netfx, so I’m not sure I follow the reasoning that because .NET Framework 4.8 may be associated with VS15, that’s all that needs to be looked at.
I guess I’ll just look at including signtool.exe in our build support package, so we can have it available that way without needing a VS/WindowsKit installed.
Visual Studio Enterprise 2019 16.11.2
HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\Microsoft\ClickOnce\SignTool
exists and containsC:\Program Files (x86)\Microsoft SDKs\ClickOnce\SignTool\
. That path exists and does containsigntool.exe
.So it looks like it should find it, but as you say, it’ll likely be because
dotnet.exe
is running in 64-bit mode and does not see that registry key.Note that if
SignFile
requires Visual Studio (Build Tools or otherwise) to be installed, that kind of defeats the purpose of enabling it. The whole point for me was to enable builds using CI without requiring installs, i.e. just doing a zip-based deployment of a .NET SDK. Any reason why signtool can’t simply ship with Windows versions of the .NET SDK?