NuGetGallery icon indicating copy to clipboard operation
NuGetGallery copied to clipboard

Support Azure Trusted Signing certificate on NuGet.org account settings

Open jozefizso opened this issue 1 year ago • 23 comments

NuGet Product(s) Involved

Other/NA

The Elevator Pitch

The Azure Trusted Signing service rotates the managed authenticode certificates each three days.

As the NuGet Gallery requires to specify a single, long lived certificate, it is not feasible to sign nuget packages with the ATS.

Additional Context and Details

@dlemstra has authored a proposal design to fix this problem: https://github.com/NuGet/Home/pull/13791

jozefizso avatar Jun 09 '24 13:06 jozefizso

@jozefizso thanks for reaching out. Could you please include details of what feature or change you are proposing? Thanks!

jebriede avatar Jun 14 '24 22:06 jebriede

The Gallery should support the code signatures made by Azure Trusted Signing. It is unfeasible to upload new signature to Gallery each three days to get the verified badge.

jozefizso avatar Jun 14 '24 22:06 jozefizso

Thanks for opening the issue @jozefizso. I agree using Trusted Signing with NuGet.org is a painful process today. You need to extract the .cer file from your signed artifact (or get it from Trusted Signing directly, perhaps) and then manually upload it to your account profile on NuGet.org.

For my own experiments I created a CLI tool to extract the .cer file and include it as a GitHub Actions artifact. Tool: https://www.nuget.org/packages/Knapcode.CertificateExtractor Workflow: https://github.com/joelverhagen/PackageLifeCycle/blob/7930b64f7e72518faf6b646187b47b46e2d64d22/.github/workflows/build.yml#L76-L87

This is better than nothing, but not much better!

joelverhagen avatar Jun 18 '24 19:06 joelverhagen

I would nice if we could get a new option to specify the Enhanced key usage that is shown on the page of our Certificate Profile inside our Trusted Signing Account. That is the same one as the bottom one that is shown here:

Enhanced key usage

And then when we upload the NuGet package the server checks if this matches and also checks if the signing of the package is done by the right authority.

dlemstra avatar Jun 18 '24 19:06 dlemstra

Supporting the Subscriber identity validation EKU as @dlemstra points out would be durable over all certificate rotations/renewals. Here is the public docs on these values: https://learn.microsoft.com/en-us/azure/trusted-signing/concept-trusted-signing-cert-management#subscriber-identity-validation-eku.

ianjmcm avatar Jun 18 '24 20:06 ianjmcm

This problem is currently impacting Git Credential Manager that ships a NuGet package that's signed by Azure Trusted Signing – would love to see some support for these sorts of certificates/signed packages, and a solution that is durable over all of the short-lived certs.

mjcheetham avatar Jun 19 '24 17:06 mjcheetham

Thanks for opening the issue @jozefizso. I agree using Trusted Signing with NuGet.org is a painful process today. You need to extract the .cer file from your signed artifact (or get it from Trusted Signing directly, perhaps) and then manually upload it to your account profile on NuGet.org.

For my own experiments I created a CLI tool to extract the .cer file and include it as a GitHub Actions artifact. Tool: https://www.nuget.org/packages/Knapcode.CertificateExtractor Workflow: https://github.com/joelverhagen/PackageLifeCycle/blob/7930b64f7e72518faf6b646187b47b46e2d64d22/.github/workflows/build.yml#L76-L87

This is better than nothing, but not much better!

@joelverhagen is the & "bin\Sign.Cli\sign.exe" something that you have created? can you share it? or do you have any pointers how to get nuget sign with trusted service? or are you using https://github.com/dotnet/sign/pull/716

jmecosta avatar Jun 20 '24 10:06 jmecosta

The "bin\Sign.Cli\sign.exe" executable is the output of the dotnet/sign project. The branch of my PR is still work in progress so it's subject to change. I have been using it locally but not yet in a pipeline.

dlemstra avatar Jun 20 '24 10:06 dlemstra

yep, just getting to that conclusion also, there are a few cli options changed but pretty much what im looking for... thank you

jmecosta avatar Jun 20 '24 10:06 jmecosta

And those options might still change because the PR is still being reviewed by the team.

dlemstra avatar Jun 20 '24 10:06 dlemstra

Yep important is the sign functionality itself if that works we can start integrating it already

jmecosta avatar Jun 20 '24 11:06 jmecosta

@dlemstra is spot on. I have a private build of sign CLI used in the pipeline links above.

But to be clear this GitHub issue tracks better support of Trusted Signing on NuGet.org (verification of signing at push time in NuGet.org) and not the sign flow which is tracked by https://github.com/dotnet/sign/issues/683.

joelverhagen avatar Jun 20 '24 13:06 joelverhagen

Has anyone seen issues where the validation fails with sign cli and trusted signing.

I'm extracting out the certificate using @joelverhagen tool

I can see the valid certificate in the nuget package explorer tool

seeing

The package was signed, but the signing certificate (SHA-1 thumbprint <thumbprint>) is not associated with your account. You must register this certificate to publish signed packages.

I have got the SHA1/256 hash and confirmed its there, and in the cert area it's showing microsoft signing there like its picked up and processed the cert.

I have tried the sign cli experimental version, jsign client, signtool as recommended in the docs and all producing the same results.

glennawatson avatar Sep 01 '24 14:09 glennawatson

no problems so far, you could try this (assuming u have done az login and your account has permissions)

dotnet tool install --global AzureTrustedSignTool dotnet tool install Knapcode.CertificateExtractor --global dotnet tool install --global sign --prerelease AzureTrustedSignTool sign --folder ./pkgs --searchpattern *.nupkg --accountname YourAccount --profilename YourSignProfile

that signs the packages and generates a .cer next to each nuget. so you can upload both at same time. So far no problems with this approach.

jmecosta avatar Sep 02 '24 07:09 jmecosta

@jmecosta I think its some sort of special rules for my package rather than a trusted signing process issue.

Eg having some packages get published (with the same single owner) and some not.

Splat had the DotNetFoundation as a owner and I know there are special rules for DNF owned packages, also its in a reserved space.

I suspect it's more rules around that rather than a legitimate certificate failure given the intermitient results about which ones pass (nupkg that never were owned by the DotNetFoundation user get published)

I have used the same steps you have used above effectively.

glennawatson avatar Sep 02 '24 08:09 glennawatson

Interesting I've never notice certificate bounded to package names. If so the error message is not really accurate

jmecosta avatar Sep 02 '24 08:09 jmecosta

@glennawatson i can confirm this also, ive just experience the same. the account is shared, and ive uploaded the CER file with my account and the other user was not able to publish the nuget...

he then re-upload the CER to his account and was able to do so. so conclusion is that the ones uploading the nugets need to have the CER files uploaded also

jmecosta avatar Sep 06 '24 10:09 jmecosta

@jmecosta, @glennawatson, @mjcheetham - folks, thank you for your input so far in this issue.

@dlemstra has opened a proposal design to address this NuGet.org limitation. Any input you have for Dirk and our team would be most appreciated over on the proposal PR: https://github.com/NuGet/Home/pull/13791!

joelverhagen avatar Sep 17 '24 14:09 joelverhagen

Would love to see this happen, as an open source developer all other alternatives involve manually signing on your local PC, which is not substainable with NuGet.org and CI, as code signing on Nuget.org is all or nothing.

ErikEJ avatar Apr 02 '25 06:04 ErikEJ

As open source developers we really need this feature.

jozefizso avatar Jun 18 '25 14:06 jozefizso

In my experience, this is a minor annoyance - at most a few minutes of extra work per day. I run this script on the days I need to generate my sync-method-generator. It creates a single certificate which is then uploaded to nuget manually (not sure if there's a way to upload certificate using APIs).

$env:AZURE_TENANT_ID = "redacted"
$env:AZURE_CLIENT_SECRET = "redacted"
$env:AZURE_CLIENT_ID = "redacted"

$version = dotnet dnx --yes nbgv get-version --format json | jq -r '.NuGetPackageVersion'

Write-Output "Version: $version"

Remove-Item "$PSScriptRoot\packages" -Recurse -Force -Confirm:$false
dotnet pack -o packages
dotnet dnx -y --prerelease sign code trusted-signing --base-directory "$PSScriptRoot/packages" "Zomp.SyncMethodGenerator.$version.nupkg" --trusted-signing-endpoint "https://eus.codesigning.azure.net" --trusted-signing-account "zomp" --trusted-signing-certificate-profile "zomp-main" -v normal

dotnet dnx --prerelease --yes Knapcode.CertificateExtractor --file "$PSScriptRoot/packages/Zomp.SyncMethodGenerator.$version.nupkg" --output packages --all

# The following was generated by ChatGPT
# Get all .cer files in current directory (you can change the path)
$certFiles = Get-ChildItem -Path "$PSScriptRoot\packages" -Filter *.cer

# Find the one with subject containing "Zomp"
$zompCert = $certFiles | Where-Object {
  try {
    $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2($_.FullName)
    $cert.Subject -like '*Zomp*'
  }
  catch {
    $false
  }
}

if ($zompCert) {
  # Keep this certificate and delete all others
  foreach ($file in $certFiles) {
    if ($file.FullName -ne $zompCert.FullName) {
      Remove-Item $file.FullName -Force
      Write-Host "Deleted: $($file.Name)"
    }
    else {
      Write-Host "Kept: $($file.Name)"
    }
  }
}
else {
  Write-Host "No certificate found with subject containing 'Zomp'"
}

virzak avatar Jul 01 '25 15:07 virzak

In my experience, this is a minor annoyance - at most a few minutes of extra work per day

Great that you found a workaround that suits your manual release flow.

For continous deployment pipelines, any manual step isn't just an annoyance but a showstopper.

fflaten avatar Jul 01 '25 16:07 fflaten

also showstoper if there are multiple sub orgs, and those sub orgs dont have access to upload the certficates (they can get apis to upload nugets)

jmecosta avatar Jul 01 '25 16:07 jmecosta