Skip to content

Pass ACS intermediate certificates to AzureSign.Core chain builder#1036

Open
Jaxelr wants to merge 2 commits into
dotnet:mainfrom
Jaxelr:feat/artifact-signing-chain-extra-store
Open

Pass ACS intermediate certificates to AzureSign.Core chain builder#1036
Jaxelr wants to merge 2 commits into
dotnet:mainfrom
Jaxelr:feat/artifact-signing-chain-extra-store

Conversation

@Jaxelr

@Jaxelr Jaxelr commented Jul 8, 2026

Copy link
Copy Markdown
Member

Problem

ArtifactSigningService fetches the full leaf + intermediates + root chain from Azure Code Signing but discards the intermediates, keeping only the leaf. This works for public trust since all the hierarchy certificates are automatically installed on windows, but not so for public trust test certificates. When the intermediates are not preinstalled in a Windows certificate store on the signing host, AzureSign.Core.AuthenticodeKeyVaultSigner's constructor throws:

InvalidOperationException: Failed to build chain for certificate.

X509Chain.Build(leaf) cannot resolve the leaf's issuer because there is no ExtraStore and (no matching CA in the local stores. AIA fetch is also unreliable on ACS test PKIs where multiple intermediates share the same Subject Name but have different keys.

Fix

Give the chain builder the intermediates that ACS already returned.

  • ICertificateProvider: add GetAdditionalCertificatesAsync as a default interface method returning an empty collection. KeyVault, CertificateStore, and existing test stubs need no changes and keep their behavior.
  • AzureSignToolSigner: fetch the collection and pass it to AuthenticodeKeyVaultSigner's existing additionalCertificates parameter, which populates X509Chain.ChainPolicy.ExtraStore before Build is called.
  • ArtifactSigningService: cache the non-leaf certificates from the P7B response and expose them through the new method. Leaf detection also switched from "last cert in the collection" to "the cert whose Subject is nobody else's Issuer" to be order-independent.
  • RSAArtifactSigning: after receiving the signature from ACS, verify it against the leaf's public key via RSA.VerifyHash and throw CryptographicException on mismatch. Cheap defense-in-depth so protocol drift, key rotation races, or transport corruption fail at the source instead of producing an unverifiable signature embedded in the artifact.

Tests

  • New ArtifactSigningServiceTests (renamed from TrustedSigningServiceTests) with two tests that build a synthetic 3-tier RSA chain, wrap it in a real PKCS#7, and verify:
    • GetCertificateAsync returns the leaf.
    • GetAdditionalCertificatesAsync returns the intermediate + root and does not contain the leaf.
  • Existing RSATrustedSigningTests.SignHash_UsesClient updated to set up the VerifyHash mock now that SignHash validates the returned signature.

What this PR does not do

AzureSign.Core's chain build succeeds after this change, but SignerSignEx3 (invoked later inside wintrust.dll) performs its own chain build that only consults Windows certificate stores. Signing hosts still need the intermediates and root reachable through the OS trust stores, exactly as before. This PR removes an incorrect failure inside our code; it does not remove the OS-level requirement that the chain be trusted on the signing machine.

@Jaxelr
Jaxelr requested a review from a team as a code owner July 8, 2026 20:56
@Jaxelr Jaxelr linked an issue Jul 8, 2026 that may be closed by this pull request
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Azure Trusted Signing fails when using Public Trust test certificates

1 participant