Open
Fix jarsigner PKIX error for non-exportable AKV certificates via AIA chain completion#47977
Conversation
Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
Co-authored-by: rujche <171773178+rujche@users.noreply.github.com>
Copilot
AI
changed the title
[WIP] Fix jarsigner warning for invalid certificate chain
Fix certificate chain ordering for jarsigner compatibility
Feb 11, 2026
3 tasks
3 tasks
Contributor
|
Hi @copilot. Thank you for your interest in helping to improve the Azure SDK experience and for your contribution. We've noticed that there hasn't been recent engagement on this pull request. If this is still an active work stream, please let us know by pushing some changes or leaving a comment. Otherwise, we'll close this out in 7 days. |
…ficates When a non-exportable Azure Key Vault certificate is used with jarsigner, the /secrets/ endpoint returns only the leaf certificate (no intermediate CAs). This causes jarsigner -verify to fail with: PKIX path building failed: unable to find valid certification path to requested target Fix: after loading certificates from the AKV secret bundle, walk the chain upward from the current top. If the top cert is not self-signed (i.e. the chain is incomplete), parse the AIA (Authority Information Access) extension (OID 1.3.6.1.5.5.7.1.1) to find the CA Issuers URL and download the missing intermediate CA certificate. Repeat until the chain reaches a self-signed root CA. Changes: - CertificateUtil: add completeChainViaAia() and downloadIssuerCertificateFromAia() methods; call completeChainViaAia() from loadCertificatesFromSecretBundleValue() after ordering - HttpUtil: add getBytes(String url) for binary (DER) certificate downloads - AiaCertificateChainTest: 10 unit tests including two PKIX path-building tests that reproduce the exact reported error and confirm it is resolved Fixes: #44267
…alidation Addresses review comments from PR #47977 review 4652501161: 1. **Leaf selection with cross-signed intermediates**: Previously used subject-DN matching only. Now verifies that potential issuers can actually validate the certificate's signature using isValidIssuer(). This prevents misselection when cross-signed/re-issued intermediates share a subject DN but have different keys. 2. **Self-signed detection in leaf selection**: Changed from subject==issuer check to signature-verified isSelfSignedCertificate(). This correctly distinguishes self-issued certs (same DN but not self-signed) from true self-signed roots. 3. **Chain-building root detection**: Changed from subject==issuer check to signature-verified isSelfSignedCertificate() when detecting chain end. Prevents early termination on self-issued-but-not-self-signed certs. 4. **Test mock timing**: Moved HttpUtil mock setup before completeChainViaAia invocation in aiaDownloadDisabledBySystemProperty test. Ensures property check regression would not trigger real network I/O. 5. **Incomplete chain completion**: When valid issuer already exists in array but at wrong position (e.g., appended as unplaced cert), now moves it to make chain contiguous. Continues loop to download next issuer instead of stopping early. All 95 tests pass.
- Fix maxDownloads counter to only decrement on actual HTTP downloads, not during certificate reordering. This prevents premature loop exit when reorganizing existing issuer certificates. - Replace string concatenation with parameterized logging in HttpUtil.getBytes() to satisfy GoodLoggingCheck. - Restore GoodLoggingCheck suppressions for CertificateUtil.java and HttpUtil.java (module requires java.util.logging for JCA provider bootstrap). Addresses: maxDownloads safety limit, GoodLoggingCheck violation in exception logging
… system property pollution
…xception, fix comments
…xception, fix comments
moarychan
approved these changes
Jul 14, 2026
moarychan
approved these changes
Jul 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
When a non-exportable DigiCert certificate in Azure Key Vault is used with
jarsigner, the signed JAR fails verification with:Fixes #44267 (regression confirmed unfixed in 2.11.0-beta.1 per this comment).
Root Cause
The Azure Key Vault
/secrets/{alias}endpoint returns only the leaf certificate for non-exportable keys (no private key, and no intermediate CA certificates when the caller only provided the leaf cert duringMergeCertificate). ThegetCertificateChain()method therefore returns a one-element array. An earlier fix (PR #41303) added intermediate cert support and PR #47977 added ordering — neither helps when the intermediate is genuinely absent.Without the intermediate CA in the chain:
jarsignerembeds only the leaf cert in the JAR signature blockjarsigner -verifycalls Java's PKIX path builder to trace leaf -> intermediate -> root CAcacerts-> path building failsSolution
After loading certificates from the AKV secret bundle, walk the chain upward. If the top certificate is not self-signed (i.e. the chain is incomplete), parse its AIA (Authority Information Access) extension (OID
1.3.6.1.5.5.7.1.1) to find thecaIssuersURL, download the missing intermediate CA certificate (DER or PEM), and append it. Repeat until the chain reaches a self-signed root CA or no AIA URL is found.This is the standard mechanism used by browsers, AzureSignTool, and major signing tools to complete certificate chains at runtime.
Example (AIA in certificate context):
In this flow, chain completion follows
CA Issuerslevel by level (leaf -> intermediate -> root) until the chain is complete or no issuer can be resolved.Implementation
Core Algorithm
findValidChainEnd()to identify true chain end (prevents interfering with extra/unplaced certs).Security Hardening
azure.keyvault.jca.disable-aia-downloadallows disabling AIA in locked-down environments.basicConstraintsor self-signed root).keyCertSignmust be set (RFC 5280 alignment).Lint and Review Follow-ups
isValidIssuerto satisfy SpotBugs (REC_CATCH_EXCEPTION).Self-Signed) with signature-based self-signed verification.findValidChainEndJavaDoc wording to match actual chain-walking direction.Changes
CertificateUtil.javacompleteChainViaAia(),downloadIssuerCertificateFromAia(),findValidChainEnd(),isSelfSignedCertificate(),isValidIssuer(); improveorderCertificateChain(); enforce KeyUsagekeyCertSign; select matching issuer from AIA bundles; improve diagnostics and lint complianceHttpUtil.javagetBytes(String url)for binary downloads (10s timeout) with exception logging for diagnosticsAiaCertificateChainTest.javaCertificateOrderTest.javaCHANGELOG.mdREADME.mdazure.keyvault.jca.disable-aia-downloadto Exposed Optionscheckstyle-suppressions.xmlCertificateUtil.java/HttpUtil.java(module continues to usejava.util.logging)Test Coverage
PKIX Path Building:
pkixPathBuildingWithoutFixFailsWithReportedError✓ Reproduces exact error from [BUG] jarsigner + jca still reports that entries in certificate chain are invalid #44267pkixPathBuildingWithFixSucceeds✓ Full chain built and PKIX validation succeedsCertificate Ordering (PEM/PKCS12):
testPemCertificateChainOrder✓ Verifies correct leaf -> intermediate -> root orderingtestPkcs12CertificateChainOrder✓ Validates PKCS12 format chain orderingtestOrderCertificateChainIncompleteRootFirst✓ Regression test: [root, leaf] input correctly orders to [leaf, root]AIA Chain Completion:
keyCertSignwhen KeyUsage present ✓azure.keyvault.jca.disable-aia-download=trueprevents AIA downloads ✓Results: 97/97 tests pass (0 failures, 29 skipped)
Customer Validation
Confirmed working by the original reporter (@manfrede) in #44267 (comment) using
azure-security-keyvault-jca-2.12.0-beta.1.jar. The AIA chain completion path executed correctly as shown in debug logs:jarsigner produced no warnings and the full chain was embedded correctly.
Backward Compatibility