Skip to content

Sign dotnetup executable for Windows and Mac#54059

Open
dsplaisted wants to merge 16 commits intodotnet:release/dnupfrom
dsplaisted:dotnetup-signing
Open

Sign dotnetup executable for Windows and Mac#54059
dsplaisted wants to merge 16 commits intodotnet:release/dnupfrom
dsplaisted:dotnetup-signing

Conversation

@dsplaisted
Copy link
Copy Markdown
Member

No description provided.

Copy link
Copy Markdown
Member

@nagilson nagilson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think copilot mostly used the existing signing implementation for the library package and copied it.

The executable production only happens in the official ci, so you'll need to run the branches in the official CI to see whether this is working or not. Here's an example signing run from the CI! https://dev.azure.com/dnceng/internal/_build/results?buildId=2958051&view=logs&j=3d5d6410-622d-51c4-8220-9d539bbf3309&t=26ffafe4-f146-5df5-f784-50f2fd9186bb

Comment thread eng/pipelines/templates/jobs/dotnetup/dotnetup-executables.yml
Comment thread eng/pipelines/templates/jobs/dotnetup/dotnetup-executables.yml Outdated
Comment thread eng/pipelines/templates/jobs/dotnetup/dotnetup-executables.yml
Comment thread src/Installer/dotnetup.sign.proj Outdated
@marcpopMSFT marcpopMSFT added the dotnetup Work items around the proposed `dotnetup` bootstrapper/toolchain management tool and library label Apr 28, 2026
dsplaisted and others added 5 commits April 30, 2026 10:20
Add code signing infrastructure for the dotnetup NativeAOT executable:

- Create src/Installer/dotnetup.sign.proj that uses Arcade's SignToolTask
  to Authenticode-sign dotnetup.exe with the Microsoft400 certificate
- Add FileSignInfo entries in eng/Signing.props for dotnetup.exe (Windows)
  and dotnetup (macOS MacDeveloperHarden, for future use)
- Restructure dotnetup-executables.yml Windows steps to sign the executable
  after publish but before copying to artifact staging directories, ensuring
  both the full publish artifact and standalone binary artifact are signed
- The signing step generates a binlog for diagnostics

macOS signing requires enableMicrobuildForMacAndLinux pipeline support and
will be addressed in a follow-up change.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Enable MicroBuild for Mac and Linux in the executable pipeline
  (enableMicrobuildForMacAndLinux: true)
- Add macOS signing step conditioned on osx-* RIDs that invokes
  dotnetup.sign.proj with TargetOS=osx and MacDeveloperHarden cert
- Update dotnetup.sign.proj to handle both platforms:
  - Windows: Authenticode via Microsoft400 for dotnetup.exe
  - macOS: MacDeveloperHarden for extensionless dotnetup binary
  - Cross-platform DotNetPath default (dotnet.exe vs dotnet)
- Split Unix pipeline steps into publish → sign → stage (matching
  the Windows structure) so signing happens before artifact copy

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Merge dotnetup executable signing into existing Installer.sign.proj
  instead of a separate dotnetup.sign.proj (per nagilson's review)
- Add DotnetupPublishDir-conditioned ItemGroup for exe/macOS signing
- Add cross-platform DotNetPath defaults (Windows/Unix)
- Delete the separate dotnetup.sign.proj
- Remove dotnetup FileSignInfo from Signing.props (dotnetup is not in
  the SDK redist — signing only happens via Installer.sign.proj in the
  standalone dotnetup pipeline)
- Update dotnetup-executables.yml to invoke Installer.sign.proj
- Add SignCheck verification steps: signtool verify (Windows),
  codesign --verify (macOS)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Generate .sha512 companion files for dotnetup executables on all
platforms (Windows via Get-FileHash, Unix via sha512sum). The checksum
files are published alongside the standalone binary artifacts.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
signtool.exe is not available on the PATH in AzDO build agents.
Replace with PowerShell's built-in Get-AuthenticodeSignature which
is always available on Windows.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
dsplaisted and others added 5 commits April 30, 2026 10:43
The "Install .NET 8.0 SDK for MicroBuild Plugin" task in
eng/common/core-templates/steps/install-microbuild.yml referenced an
undeclared microBuildOutputFolder parameter, so the SDK installation
path resolved to /.dotnet on Linux/macOS - a read-only location that
caused the task to fail with EROFS in cross-build containers.

Backport the upstream arcade fix:
  - Declare microBuildOutputFolder parameter defaulting to
    Agent.TempDirectory/MicroBuild.
  - Install the SDK at microBuildOutputFolder/.dotnet-microbuild.

Also restrict enableMicrobuildForMacAndLinux on the dotnetup
executables job to osx-* RIDs, since the Linux jobs do not sign and
do not need the MicroBuild plugin at all.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MicroBuildSigningPlugin@4 on macOS requires a pipeline variable literally
named TeamName, not just the arcade _TeamName convention or the env var
set by install-microbuild.yml. Add it alongside _TeamName so osx signing
jobs no longer fail with "TeamName variable is required to use MicroBuild".

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Microsoft.DotNet.SignTool unconditionally requires PkgToolPath when running
on macOS, even when only signing a single Mach-O binary (no .pkg/.app
bundles). Match the pattern used by arcade Sign.proj:

- Add a PackageDownload for Microsoft.DotNet.MacOsPkg.Cli (osx-only) using
  the same version as the SignTool package, since both ship from the same
  arcade build.
- Wire MacOSPkgCliItem into the SignToolTask via PkgToolPath.
- Add an explicit restore step in the osx sign job, since Installer.sign.proj
  is not part of dotnetup.slnf and dotnetup signing is the only consumer of
  Microsoft.DotNet.MacOsPkg.Cli.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The MicroBuild signing process spawns a child MSBuild on Round0-Sign.proj
whose binlog is written to artifacts/log/Sign/. Publish that directory as
a pipeline artifact for osx jobs so the actual signing failure is
diagnosable.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The MicroBuild ESRP signing plugin needs SYSTEM_ACCESSTOKEN at runtime
to acquire a federated OIDC token. Without it, SignFiles fails with
'Access token is not available' from ESRPCliDll.EncryptAccessToken /
GetFederatedTokenData.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copy link
Copy Markdown
Member

@nagilson nagilson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will verify the Mac signature on Monday, but the changes look great! Thank you for including a verification of the authenticode, I was also able to verify the signature.

One question I have is if we could try using Microsoft402 for Windows

<FileSignInfo Include="dotnetup.exe" CertificateName="Microsoft402" />
<FileExtensionSignInfo Include=".exe" CertificateName="Microsoft402" />

The dotnetup executable is still being rejected by windows defender smart screen because microsoft 400 is an internal EKU (this is my bad for suggesting to use the library package signature) but I think Microsoft402 is an EV Authenticode which will pass defender. MicrosoftDotNet500 is also a standard we use but this does not have automatic reputation which means it will still get blocked by defender until it has enough downloads, to my knowledge.


<!-- SignTool requires explicit dotnet path; default to repo-local SDK. -->
<DotNetPath Condition="'$(DotNetPath)' == ''">$(RepoRoot).dotnet\dotnet.exe</DotNetPath>
<DotNetPath Condition="'$(DotNetPath)' == '' and '$(OS)' == 'Windows_NT'">$(RepoRoot).dotnet\dotnet.exe</DotNetPath>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch to fix this executable ending!

Copy link
Copy Markdown
Member

@nagilson nagilson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The signature fails on Mac 'dotnetup cannot be opened because apple cannot check it for malicious software.'

I believe we need to use MacDeveloperWithNotarization as a starting point.

I also think this may be a potential concern: Distributing a bare Mach-O binary in a .zip can lose the notarization ticket staple (which is stored as an xattr). Apple recommends distributing notarized binaries inside a .dmg, .pkg, or using stapler staple on the binary before zipping (the ticket gets embedded in the binary's code directory).

We should consider making the pipeline run xcrun stapler staple dotnetup after notarization succeeds and before archiving. You may want to see how others are using it in our org or if dnceng can do it for us: https://github.com/search?q=org%3Adotnet+xcrun&type=code

dsplaisted and others added 6 commits May 5, 2026 13:53
…on macOS

- Switch Windows dotnetup.exe signing cert from Microsoft400 to Microsoft402.
  Microsoft400 is an internal EKU; Defender SmartScreen still blocks the
  binary. Microsoft402 is EV Authenticode and has automatic reputation,
  which lets the executable pass SmartScreen.

- Switch macOS dotnetup signing cert from MacDeveloperHarden to
  MacDeveloperWithNotarization so the binary is both signed and notarized
  by Apple. Without notarization, Gatekeeper blocks execution with
  ''dotnetup cannot be opened because Apple cannot check it for malicious
  software''.

- Add a pipeline step that runs `xcrun stapler staple` on the notarized
  binary before it is archived. Distributing a bare Mach-O inside a .zip
  can lose the notarization ticket (it is otherwise stored as an xattr).
  Stapling embeds the ticket into the binary''s code directory so it
  survives zipping.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The MicroBuild signing plugin reports ''Could not find the specified
Authenticode cert MacDeveloperWithNotarization''. The correct cert name
in MicroBuild is `MacDeveloperHardenWithNotarization` (matches the
pattern used by dotnet/cli-lab).

Also publish the per-RID signing logs (artifacts/log/Sign) for Windows
jobs in addition to macOS. The Windows sign step is also failing in
Round0-Sign.proj exit 1, but the underlying SignFiles error from the
child MSBuild is only captured in those logs and is not currently
published, so we cannot see why Microsoft402 is being rejected (or if
it is even what is failing).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
MacDeveloperHardenWithNotarization is a *virtual* cert name handled by
Microsoft.DotNet.SignTool: the task translates it to the real underlying
MacCertificate (MacDeveloperHarden) plus a notarize step. The mapping is
not built in — it must be supplied via the SignToolTask.CertificatesSignInfo
parameter (an item group with MacCertificate and MacNotarizationAppName
metadata).

Without this, MicroBuild''s SignFiles plugin sees the virtual name as a
literal cert name, fails to find it, and reports''Could not find the
specified Authenticode cert MacDeveloperHardenWithNotarization''.

This matches how dotnet/arcade''s own Sign.props declares the mapping for
the full set of MacDeveloper*WithNotarization virtual certs.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Microsoft402 (EV) is documented in arcade but not actually provisioned in

MicroBuild.Plugins.Signing 1.1.1271 (no ESRPCerts/402.json), causing the

Windows sign step to fail. MicrosoftDotNet500 is the .NET-specific Authenticode

cert documented for cases where Microsoft400 is blocked by Defender SmartScreen.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
NativeAOT publish on osx produces dotnetup.dSYM next to the binary. The dSYM

bundle contains an unsigned Mach-O DWARF file. When the sign+notarize archive

is submitted to Apple, the unsigned dSYM Mach-O fails notarization with

'Archive contains critical validation errors', causing the whole submission

to be rejected. dSYMs are debug data not needed by end users; remove them

before signing.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Instead of deleting the NativeAOT-produced dotnetup.dSYM bundle before Mac

signing, move it into a sibling staging directory and publish it as a

separate 'dotnetup-executable-dsym-<rid>' pipeline artifact.

The dSYM contains DWARF debug info useful for symbolicating native crash

dumps later. We don't want it in the notarization archive (it's an unsigned

Mach-O that causes Apple's notarytool to reject the whole submission), but

there's no reason to discard it entirely.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@dsplaisted dsplaisted marked this pull request as ready for review May 6, 2026 01:29
Copilot AI review requested due to automatic review settings May 6, 2026 01:29
@dsplaisted dsplaisted requested a review from a team as a code owner May 6, 2026 01:29
@dsplaisted
Copy link
Copy Markdown
Member Author

I've updated this to use Microsoft500 for Windows as it looks like MicroBuild doesn't support Microsoft402.

I've also updated the Mac signing to do the notarization and stapling. However, there seems to be a signing outage, so I'm not sure if it works all the way.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the dotnetup build pipeline and signing project to produce signed dotnetup executables on Windows (Authenticode) and macOS (codesign + notarization), and publishes related artifacts (logs, binlogs, dSYM, checksums) for diagnostics and distribution.

Changes:

  • Extend Installer.sign.proj to sign dotnetup/dotnetup.exe, including macOS notarization support via CertificatesSignInfo and macOS pkg tooling wiring.
  • Update the dotnetup executable pipeline job to run signing/verification steps for Windows and macOS, publish signing logs, and generate SHA-512 checksums (plus dSYM handling on macOS).
  • Adjust MicroBuild installation on non-Windows agents and set required pipeline variables for MicroBuildSigningPlugin usage.

Reviewed changes

Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.

File Description
src/Installer/Installer.sign.proj Adds dotnetup executable signing rules for Windows and macOS, plus macOS SignTool prerequisites (PkgToolPath + cert mapping).
eng/pipelines/templates/jobs/dotnetup/dotnetup-executables.yml Adds signing, signature verification, signing-log publishing, dSYM staging (macOS), and checksum generation to dotnetup executable jobs.
eng/common/core-templates/steps/install-microbuild.yml Changes where the MicroBuild helper .NET SDK is installed on Mac/Linux and introduces a parameterized install folder.
.vsts-dnup-ci.yml Defines TeamName pipeline variable required by MicroBuildSigningPlugin on non-Windows agents.

Comment on lines +45 to +50
<FileExtensionSignInfo Include=".exe" CertificateName="MicrosoftDotNet500" />
<FileSignInfo Include="dotnetup.exe" CertificateName="MicrosoftDotNet500" />
<ItemsToSign Condition="'$(OS)' == 'Windows_NT'" Include="$(DotnetupPublishDir)dotnetup.exe" />
<FileSignInfo Include="dotnetup" CertificateName="MacDeveloperHardenWithNotarization" />
<ItemsToSign Condition="'$(TargetOS)' == 'osx'" Include="$(DotnetupPublishDir)dotnetup" />
<CertificatesSignInfo Condition="'$(TargetOS)' == 'osx'" Include="MacDeveloperHardenWithNotarization" MacCertificate="MacDeveloperHarden" MacNotarizationAppName="dotnet" />
Comment on lines 28 to 33
displayName: Install .NET 8.0 SDK for MicroBuild Plugin
inputs:
packageType: sdk
version: 8.0.x
installationPath: ${{ parameters.microBuildOutputFolder }}/.dotnet
installationPath: ${{ parameters.microBuildOutputFolder }}/.dotnet-microbuild
workingDirectory: ${{ parameters.microBuildOutputFolder }}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

dotnetup Work items around the proposed `dotnetup` bootstrapper/toolchain management tool and library

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants