Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Feb 11, 2026

jarsigner fails to validate JARs signed with non-exportable Azure Key Vault certificates due to certificate chain ordering issues. BouncyCastle's PKCS12 parser returns certificates in unpredictable order, causing "PKIX path building failed" errors.

Changes

  • Added CertificateUtil.orderCertificateChain() – Identifies the leaf certificate (one not issuing others) and builds chain leaf→intermediate(s)→root by following issuer relationships
  • Modified loadCertificatesFromSecretBundleValue() – Always orders certificates before returning, regardless of PEM or PKCS12 format
  • Added tests – Validates PEM/PKCS12 ordering, reversed chain correction, and edge cases

Implementation

The ordering algorithm:

  1. Find leaf certificate: the cert that doesn't issue any other cert in the chain
  2. Walk issuer relationships from leaf to root
  3. Fallback to original order if chain cannot be determined
// Before: certificates may be in any order
Certificate[] certs = loadCertificatesFromSecretBundleValue(pemString);

// Now: always ordered as leaf → intermediate(s) → root CA
// Required by jarsigner for PKIX path validation

Handles edge cases gracefully (null, empty, single cert) and maintains backward compatibility.

Original prompt

This section details on the original issue you should resolve

<issue_title>[BUG] jarsigner + jca still reports that entries in certificate chain are invalid</issue_title>
<issue_description>Describe the bug
When using a valid, DigiCert issued, non-exportable Azure Key Vault certificate to sign a .jar file with jarsigner + jca 2.10.0, jarsigner will produce a warning.

Issue seems to persist after bugfix, referencing #41832

Exception or Stack Trace
Warning: This jar contains entries whose certificate chain is invalid. Reason: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

To Reproduce
Steps to reproduce the behavior are pretty much identical to #44085:

Create new version of a non-exportable code signing certificate from Azure Key Vault (RSA-HSM, 4096)
Sign the CSR through DigiCert
Merge the signing request with Azure Key Vault
Configure the app registration with secret, along with RBAC on Azure Key Vault for access
Open Windows Terminal and run the Code Snippet below (With environment variables declared, disregard line feeds):

jarsigner.exe
-keystore NONE
-storetype AzureKeyVault
-signedjar signed.jar original.jar xxx
-verbose
-storepass ""
-providerName AzureKeyVault
-providerClass com.azure.security.keyvault.jca.KeyVaultJcaProvider
-J--module-path="azure-security-keyvault-jca-2.10.0.jar"
-J--add-modules="com.azure.security.keyvault.jca"
-J-Dazure.keyvault.uri="https://xxx.vault.azure.net/"
-J-Dazure.keyvault.tenant-id="%TENANT%"
-J-Dazure.keyvault.client-id="%CLIENT_ID%"
-J-Dazure.keyvault.client-secret="%SECRET%"
-tsa http://timestamp.digicert.com

It will produce the following output:

Feb. 19, 2025 1:59:41 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient <init>
INFORMATION: Using Azure Key Vault: https://xxx.vault.azure.net/
Feb. 19, 2025 1:59:41 PM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getLoginUri
INFORMATION: Getting login URI using: https://xxx.vault.azure.net/certificates?api-version=7.1
Feb. 19, 2025 1:59:42 PM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getLoginUri
INFORMATION: Obtained login URI: https://login.microsoftonline.com/xxx
Feb. 19, 2025 1:59:42 PM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getAccessToken
INFORMATION: Getting access token using client ID / client secret
Feb. 19, 2025 1:59:43 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey
INFORMATION: Getting key for alias: xxx
Feb. 19, 2025 1:59:43 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate
INFORMATION: Getting certificate for alias: xxx
Feb. 19, 2025 1:59:43 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificateChain
INFORMATION: Getting certificate chain for alias: xxx
Feb. 19, 2025 1:59:43 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey
INFORMATION: Getting key for alias: xxxov
Feb. 19, 2025 1:59:43 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate
INFORMATION: Getting certificate for alias: xxxov
Feb. 19, 2025 1:59:44 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificateChain
INFORMATION: Getting certificate chain for alias: xxxov
Feb. 19, 2025 1:59:44 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient <init>
INFORMATION: Using Azure Key Vault: https://xxx.vault.azure.net/
Feb. 19, 2025 1:59:44 PM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getLoginUri
INFORMATION: Getting login URI using: https://xxx.vault.azure.net/certificates?api-version=7.1
Feb. 19, 2025 1:59:44 PM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getLoginUri
INFORMATION: Obtained login URI: https://login.microsoftonline.com/xxx
Feb. 19, 2025 1:59:44 PM com.azure.security.keyvault.jca.implementation.utils.AccessTokenUtil getAccessToken
INFORMATION: Getting access token using client ID / client secret
Feb. 19, 2025 1:59:44 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey
INFORMATION: Getting key for alias: xxx
Feb. 19, 2025 1:59:44 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate
INFORMATION: Getting certificate for alias: xxx
Feb. 19, 2025 1:59:45 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificateChain
INFORMATION: Getting certificate chain for alias: xxx
Feb. 19, 2025 1:59:45 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient getKey
INFORMATION: Getting key for alias: xxxov
Feb. 19, 2025 1:59:45 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificate
INFORMATION: Getting certificate for alias: xxxov
Feb. 19, 2025 1:59:45 PM com.azure.security.keyvault.jca.implementation.KeyVaultClient getCertificateChain
INFORMATION: Getting certificate...

</details>



<!-- START COPILOT CODING AGENT SUFFIX -->

- Fixes Azure/azure-sdk-for-java#44267

<!-- START COPILOT CODING AGENT TIPS -->
---

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more [Copilot coding agent tips](https://gh.io/copilot-coding-agent-tips) in the docs.

Copilot AI and others added 4 commits February 11, 2026 02:26
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
Copilot AI requested a review from rujche February 11, 2026 02:36
@rujche rujche added azure-spring All azure-spring related issues azure-spring-jca labels Feb 11, 2026
@rujche rujche added this to the 2026-03 milestone Feb 11, 2026
@rujche rujche moved this from Todo to In Progress in Spring Cloud Azure Feb 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

azure-spring All azure-spring related issues azure-spring-jca

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

[BUG] jarsigner + jca still reports that entries in certificate chain are invalid

2 participants