Last updated: Nov 1, 2025
Code signing is a critical security practice in modern software development, especially for Java applications. Whether you’re building desktop software, enterprise tools, or distributing JAR files, signing your code with a trusted Java code signing certificate ensures authenticity and integrity for your users. Without a valid certificate, Java applications often trigger security warnings such as “Application Blocked by Security Settings” or “Unsigned application requesting unrestricted access.” These warnings not only discourage users from running your application—they also create a perception of distrust.
Unlike web-based certificates (used for SSL/TLS), Java code signing certificates are specifically designed to digitally sign JAR files and protect end users from tampering, spoofing, or malware injection. When your Java app is correctly signed, the Java Runtime Environment (JRE) recognizes that the code has not been modified since it was signed and identifies the publisher who signed it.
This guide walks through everything you need to know—from understanding what Java code signing certificates are, to generating keystores, signing JAR files, troubleshooting common errors, and implementing best practices for long-term certificate usage. Whether you’re a solo Java developer or part of a DevOps team handling secure deployment pipelines, this guide will help you set up, sign, verify, and maintain signed Java applications confidently.
What Is a Java Code Signing Certificate?
A Java code signing certificate is a digital certificate used to apply a cryptographic signature to Java applications—typically packaged as JAR, WAR, or EAR files. This signature verifies three critical aspects for users and systems running Java software:
-
Authenticity – The software is published by a verified entity (individual or organization).
-
Integrity – The code has not been modified since it was signed.
-
Trust – The operating system or Java Runtime Environment (JRE) recognizes the certificate as valid and trusted.
Java code signing certificates function much like other types of digital certificates but are specifically designed to work with Java’s security model. They are issued by a Certificate Authority (CA) such as DigiCert, Sectigo, or GlobalSign, after a validation process.
How Java Code Signing Works
When a developer signs a JAR file using a certificate, the signing process embeds a digital signature and corresponding public key into the file. Along with this, the chain of trust from the signing certificate to the issuing CA is also included. When the user runs the application, the Java Runtime Environment performs three security checks:
-
Does the signature match the application?
-
Is the signing certificate still valid (not expired or revoked)?
-
Is the certificate issued by a trusted CA?
If all checks pass, the app runs with full permissions and shows the publisher’s name as the verified signer. If not, the user will see security warnings or the application may be blocked entirely.
Why Code Signing Matters in Java
Unlike web applications that run inside the safety of a browser sandbox, Java desktop and enterprise applications have access to local system resources. Unsigned or improperly signed Java apps present a security risk because they could be tampered with or impersonated by malicious actors.
Some reasons to sign your Java code include:
-
Preventing modification and re-distribution of your app by unauthorized sources
-
Removing “Unknown publisher” warnings during installation
-
Complying with enterprise and vendor security policies
-
Reducing the risk of your app being flagged as harmful by antivirus tools or operating systems
Where Java Code Signing Is Used
Java code signing applies to scenarios including:
-
JAR files (Java desktop applications, browser applets, executable archives)
-
Java Web Start applications (deprecated, but still in use in legacy corporate systems)
-
Swing or JavaFX GUI apps
-
Enterprise Java deployments (WAR/EAR files in app servers like Tomcat or JBoss)
Whether you’re developing internal tools or distributing public-facing software, signing your Java applications is no longer optional—it’s an essential security practice.
Types of Java Code Signing Certificates
Before you can sign your Java applications, it’s important to understand the different types of Java code signing certificates available. The certificate you choose affects not only the setup process but also the level of trust your signed Java application receives from users and systems.
Java code signing certificates come in two main types:
-
Standard Code Signing Certificates
-
Extended Validation (EV) Code Signing Certificates
Each type is issued by a trusted Certificate Authority (CA) such as Sectigo, DigiCert, GlobalSign, and GoDaddy, and both are compatible with tools like keytool and jarsigner used for Java JAR signing.
Standard Java Code Signing Certificates
A Standard Java Code Signing Certificate offers the basic functionality required to sign Java applications. Once the certificate has been issued, you can use it to digitally sign JAR files via the Java Keystore and tools like jarsigner.
Key Features:
-
Identity verification for an individual or organization
-
Removes “Unknown Publisher” warnings
-
Compatible with Java Runtime Environment (JRE)
-
Works with timestamping servers for long-term signature validation
-
Fast issuance (usually 1–3 days)
Best for:
-
Developers distributing standalone Java apps
-
Small software vendors
-
Companies not yet needing hardware-level validation
EV (Extended Validation) Java Code Signing Certificates
Extended Validation (EV) Code Signing Certificates offer a higher degree of trust and are used by organizations that need to comply with strict enterprise or security policies. EV certificates require a more thorough validation process and often use hardware security modules (HSMs) or USB tokens to store private keys.
Key Features:
-
Highest level of publisher verification
-
Private key generated and stored on external hardware (USB token or HSM)
-
Required for certain enterprise deployments and highly sensitive environments
-
Stronger protection against certificate theft or tampering
Best for:
-
Enterprise-grade Java applications
-
Government, healthcare, financial, or public-sector tools
-
Companies wanting to protect their signing keys with hardware-level security
Comparison Table: Standard vs EV Java Code Signing Certificates
| Feature | Standard Java Code Signing | EV Java Code Signing |
|---|---|---|
| Identity verification | Basic | Extended validation |
| Key storage | Local machine or keystore | Hardware token (HSM) |
| Removes “Unknown Publisher” | Yes | Yes |
| Requires USB token | No | Yes |
| Ideal for | Individual developers | Large organizations |
| Issuance Speed | 1–3 business days | 3–7 business days |
| Cost | Lower | Higher |
Certificate Providers for Java Code Signing
Popular providers of Java code signing certificates include:
-
Sectigo (formerly Comodo Code Signing)
-
DigiCert Java Code Signing Certificate
-
GlobalSign Code Signing CA
-
GoDaddy Java Code Signing
-
SSL.com Code Signing Certificates
When choosing a provider, consider support, timestamp server availability, pricing, issuance time, and compatibility with Java Development Kits (JDK) and Java Runtime Environment (JRE).
Prerequisites Before You Start
Before you begin setting up and signing Java applications using a Java code signing certificate, it’s important to have the right tools, files, and environment in place. This section outlines everything you need to successfully generate a certificate signing request (CSR), install the certificate into a Java Keystore, and use it to sign your Java JAR files.
Having these prerequisites ready will help ensure a smooth setup and avoid common errors like “Keystore not found,” “Cert chain not trusted,” or “Failed to sign JAR – no private key matching alias.”
1. Java Development Kit (JDK)
You will need the Java Development Kit (JDK) installed on your system, version 7 or higher. JDK includes two essential tools for code signing:
-
keytool— to manage keystores and import certificates -
jarsigner— to sign JAR files using certificates stored in a keystore
To check JDK installation, run:
You should also confirm the path to your JDK’s bin directory is included in your system’s PATH variable.
2. Java Keystore (JKS or PKCS12)
In Java, certificate keys are stored in a special secure file called a keystore. You can use either:
-
JKS (Java Keystore) — original Java-specific keystore format
-
PKCS12 (.p12 or .pfx format) — industry-standard format, required for EV certificates or cross-tool use
If you don’t already have one, you can generate a Java keystore and private key using:
You will need to remember both the keystore password and the alias name, as they will be required later when signing your JAR file.
3. Certificate Signing Request (CSR)
To obtain a Java code signing certificate from a Certificate Authority (CA), you’ll need to submit a Certificate Signing Request (CSR). This is a text file generated using the private key stored in your keystore.
You can generate a CSR with:
The CSR will contain your public key and organization information, which will be validated by the CA before issuing the certificate.
4. Code Signing Certificate From a Certificate Authority
After submitting your CSR, your CA will verify your identity and issue a Java code signing certificate. This will typically be provided in one of the following formats:
-
CRT or CER (Base64)
-
PFX or P12 (PKCS#12 format, often for EV certificates)
-
Intermediate CA bundle and root certificates
If your certificate is in .cer or .pem format, you will need to import it into the keystore. If it’s provided as a .pfx file, you’ll need to convert it into .jks using keytool or OpenSSL.
5. Timestamp Server URL (Optional but Recommended)
When signing a JAR file, it’s recommended to add a timestamp so that the signature remains valid even after the certificate expires. Most code signing CAs provide a free time-stamping service. Common timestamp URLs include:
You’ll need these URLs when running the jarsigner command later.
6. Administrator Access / Secure Environment
Since your private key must remain protected, high-security requirements include:
-
Signing from a secure or offline system
-
Restricted access to keystores or hardware tokens
-
Backing up keystore files to encrypted storage
For EV certificates, your private key will be stored on a USB token or HSM device. You’ll need access to that hardware during certificate installation and signing.
How to Set Up a Java Code Signing Certificate
Setting up a Java code signing certificate involves preparing a keystore, generating a CSR (Certificate Signing Request), completing CA validation, and importing the issued certificate chain into a Java Keystore (JKS or PKCS12). The end goal is to have a keystore that contains your private key and the full certificate chain (leaf, intermediate, and root) so you can sign Java applications and JAR files reliably with jarsigner. This section provides a complete, repeatable procedure that works across Windows, macOS, and Linux, using standard Java tools such as keytool and, where needed, OpenSSL for format conversion. It also covers nuances for EV (Extended Validation) Java code signing certificates, which often ship in a PKCS#12 container and require hardware tokens.
Step 1 — Plan your keystore format (JKS vs PKCS12) and alias strategy
A successful setup begins with choosing the right keystore format and deciding on consistent alias names. Java historically used JKS (.jks), while PKCS12 (.p12 / .pfx) is now the industry-standard and is fully supported by modern JDKs. If you expect to interoperate with non-Java tooling (CI/CD, signing services, HSMs), PKCS12 is the most portable choice. For EV code signing certificates, your CA may provide a PFX/PKCS12 bundle that you import directly, or it may require using a hardware token or HSM—those environments typically expose a PKCS#11 interface to Java.
It is equally important to choose a stable alias (e.g., codesign) and use it consistently throughout key generation, CSR creation, and signing. The alias ties the private key to the eventual certificate chain in your Java keystore.
Step 2 — Generate a private key and keystore
If you are obtaining a standard Java code signing certificate (non-EV) and want to create your own private key, generate it in a keystore you control. Use RSA 3072 or RSA 2048; for most CAs, RSA 2048 remains acceptable, but RSA 3072 is a stronger baseline.
JKS example:
PKCS12 example:
Use a strong keystore password and key password, and record them in a secure secrets manager. If your organization requires elliptic curve (EC) keys, confirm CA support before generating -keyalg EC.
Step 3 — Create a CSR (Certificate Signing Request)
A CSR binds your identity to the key pair you just created and is submitted to the Certificate Authority for Java code signing certificate issuance.
If you used a JKS, change keystore to codesign.jks. The CSR (codesign.csr) is a Base64 text file. Submit this CSR in your CA’s order portal for a Java code signing certificate (Standard or EV). For organizational certificates, ensure your legal entity details match public records; EV validation will also require additional documentation and a callback.
Step 4 — Complete CA validation and download all issued files
After validation, your CA will issue the code signing certificate. You may receive:
-
A leaf certificate (e.g.,
.cer,.crt, or.pem) -
One or more intermediate CA certificates
-
Optionally a PFX/PKCS12 bundle (common for EV)
-
Timestamp server URLs (for use during signing)
Always collect the entire chain: leaf + intermediate(s). Do not import a root certificate manually into your code signing keystore unless your CA instructs you—Java and OS truststores already contain roots.
Step 5 — Import the CA chain and the leaf certificate into your keystore
If you generated the key and CSR locally, your keystore already holds the private key under your alias. You must now import the CA chain and the issued leaf certificate so that the alias ends up with a PrivateKeyEntry that includes the full certificate chain.
-
Import intermediate(s) first (each with a unique alias, e.g.,
intermediate-1,intermediate-2):
-
Import the leaf certificate to the same alias that holds the private key (here,
codesign). This step “mates” the issued cert to your key:
-
Verify the entry type and chain:
Confirm the Entry type: PrivateKeyEntry for alias codesign and that the certificate chain shows the leaf followed by intermediate CA(s).
Step 6 — If your CA provided a PFX/PKCS12 bundle (common with EV), import or convert it
Many EV Java code signing certificates arrive as a .pfx (PKCS#12) bundle. If your signing will happen on the same machine, you can import this file directly into a new keystore or convert it. Two common workflows:
A) Use the PFX directly with Java (supported in modern JDKs):
You can pass this keystore to jarsigner with -keystore ev_codesign.pfx -storetype PKCS12.
B) Convert PFX to JKS (if legacy tooling demands .jks):
If the PFX is bound to a hardware token (USB/HSM) via vendor drivers, you may need a PKCS#11 configuration. In that case, jarsigner can access the device through the PKCS#11 provider; consult your token vendor for the module path and sample java.security provider config.
Step 7 — Normalize certificate formats when needed (OpenSSL helpers)
Some CAs provide leaf and intermediate certificates as .cer or .pem. Java accepts Base64-encoded X.509, but if you receive DER or need to convert to PEM, you can use OpenSSL:
DER to PEM:
Bundle intermediate + leaf to a single PEM (handy for record-keeping):
You still import intermediate(s) and the leaf separately with keytool as described above.
Step 8 — Secure your keystore and private keys
Your Java code signing certificate is only as secure as its private key. Store keystores on encrypted disks, restrict permissions, and back up the keystore and passwords in a secure secrets manager. For EV certificates, the private key resides on a hardware token or HSM—keep custody policies, PINs, and token inventory under strict control. Rotate passwords periodically and implement least-privilege access for build servers that perform jarsigner operations.
Step 9 — Configure timestamping for long-term validity
Timestamping preserves the validity of a code signature after the certificate expires, proving the JAR was signed when the certificate was valid. Collect a timestamp server URL from your CA (e.g., DigiCert, Sectigo, GlobalSign). You will pass it to jarsigner with -tsa during the signing step (covered in the next section), ensuring your Java application remains trusted long past the certificate’s end date.
Step 10 — Validate the keystore entry before you proceed to signing
Before moving on to signing JARs, verify that your keystore has:
-
A
PrivateKeyEntryat the signing alias (e.g.,codesign) -
The full certificate chain (leaf + intermediate(s))
-
Correct store and key passwords
Quick self-test:
If Entry type is trustedCertEntry instead of PrivateKeyEntry, you imported the certificate to the wrong alias (one that doesn’t hold the private key). Re-import the leaf to the key-holding alias, or re-trace CSR creation to ensure the same keystore and alias were used throughout.
Common setup pitfalls and how to avoid them
-
Mismatch between CSR keystore and import keystore: Always import the issued leaf into the same keystore and alias used to create the CSR; otherwise you won’t have a private key match.
-
Forgetting to import intermediate CA certificates: Missing intermediates cause “certificate chain not trusted” warnings when signing and verifying. Import intermediates before the leaf.
-
Using JRE instead of JDK tools: Ensure you’re invoking
keytool/jarsignerfrom the JDK installation, not the JRE, to avoid unsupported options or older providers. -
Weak algorithms: Use
SHA256withRSAor stronger. Avoid SHA-1; modern JVMs may reject it under algorithm constraints. -
EV token driver issues: Install vendor middleware and confirm the PKCS#11 module path before attempting to sign from CI/CD.
How to Sign a Java JAR File
With your Java code signing certificate set up in a Java Keystore (JKS or PKCS12) and your private key available under a known alias, you are ready to sign Java applications—most commonly JAR files. The goal of JAR signing is to attach a verifiable digital signature and certificate chain so that the Java Runtime Environment (JRE) and end users can confirm the publisher’s identity and that the archive has not been altered since signing. In practice, you will use jarsigner (from the JDK) to sign and optionally timestamp your JARs, and then you will verify the signature locally before distributing the artifact.
Signing is not merely a formality. It directly reduces security warnings, enables policy-compliant execution in enterprise environments, and creates a defensible audit trail for releases. This section provides a complete workflow that emphasizes correctness, long-term validity via timestamping, and compatibility with modern JVM algorithm constraints.
Understand the moving parts: keystore, alias, algorithms, and timestamping
Before running commands, align on four fundamentals:
-
Keystore and alias:
jarsignerneeds the keystore path, its password, and the alias that holds aPrivateKeyEntry. If you see “no private key” or “trustedCertEntry,” it means the alias doesn’t hold a private key or you imported the certificate to the wrong alias. -
Algorithms: Modern JVMs enforce algorithm constraints. Use SHA-256 or stronger digests and signatures (for example,
-digestalg SHA-256 -sigalg SHA256withRSA). Avoid SHA-1, which may be rejected. -
Full certificate chain: Ensure your alias’s entry includes the leaf and intermediate CA certificates. Missing intermediates can lead to trust errors on client machines.
-
Timestamping: A timestamp server (
-tsaURL) proves the JAR was signed while your Java code signing certificate was valid. Without timestamping, signatures may be considered invalid after the certificate expires.
Basic signing with jarsigner (PKCS12 keystore)
The following example signs app.jar using a PKCS12 keystore. Adjust paths, passwords, and alias names to match your environment.
Explanation of the important options:
-
-keystoreand-storetypepoint to your keystore (PKCS12 or JKS). -
-storepassand-keypassprovide the keystore and key passwords (prefer using a secure credential store in CI). -
-digestalgand-sigalgpick modern algorithms compatible with JVM security policies. -
The last two parameters are the path to the JAR and the signing alias (
codesign).
This produces a signed JAR in place, embedding signature files (e.g., META-INF/CODESIGN.SF and META-INF/CODESIGN.RSA).
Add timestamping for long-term signature validity
Including a timestamp server is strongly recommended. Most CAs publish a free TSA URL. With timestamping, even after the Java code signing certificate expires, the signature stays valid because it can be proven the JAR was signed while the certificate was active.
If your CA provides multiple TSAs, select one with good uptime. Some TSAs support RFC 3161; jarsigner will negotiate automatically.
Signing with a JKS keystore
If you are using a traditional JKS keystore, the command changes only by omitting -storetype PKCS12 and pointing to the .jks file:
Ensure that the alias codesign in your JKS holds a PrivateKeyEntry with the full certificate chain imported earlier.
Verify a signed JAR locally
Verification confirms that the JAR contains a valid signature, that it matches the content, and that the certificate chain is correctly embedded.
What to look for:
-
“jar verified.” indicates success.
-
The output lists the signer certificate, chain details, and each entry’s digest verification.
-
Warnings about “This jar contains entries whose certificate chain is not validated” point to missing intermediates or truststore issues. Revisit your keystore import sequence if this appears.
You can also extract and inspect the signature metadata under META-INF/ to confirm that the .SF and .RSA/.DSA files are present and reference the expected algorithms.
Best-practice flags and options for production releases
While jarsigner works with defaults, production builds benefit from explicit, modern settings:
-
Use
-sigalg SHA256withRSAand-digestalg SHA-256(or appropriate EC equivalents). -
Always include
-tsa <URL>for timestamping. -
If you sign multiple times (e.g., rebranding), use a distinct alias to avoid confusion.
-
Keep the signed artifact immutable; modifying a signed JAR invalidates the signature.
For very large JARs or reproducible builds, ensure your build system produces the same byte-for-byte archive prior to signing. Differences in file order or timestamps can alter digests and complicate validation in strict environments.
Sign multiple JARs efficiently during a build
In CI/CD, you’ll often sign many JARs. A simple shell loop helps standardize parameters and prevents inconsistent flags:
Store secrets in the CI’s secret manager and inject them at runtime. Do not hardcode passwords into scripts or version control.
Maven and Gradle integration (optional but recommended for consistency)
Automating Java JAR signing in your build tool ensures every release is signed the same way.
Maven example (using maven-jarsigner-plugin):
Gradle example (using an Exec task):
These integrations keep your Java code signing certificate usage consistent across environments and minimize human error.
Common signing errors and corrective actions
Even with a correct setup, a few predictable issues occur during JAR signing. Here are the most frequent ones and how to resolve them quickly:
-
“jarsigner: unable to sign jar: java.lang.RuntimeException: keystore was tampered with, or password was incorrect”
Use the correct keystore and key passwords. Confirm you’re using the right file and that it’s not corrupted. -
“The signer certificate is self-signed” or “No certificate from a trusted CA”
You imported only a self-signed certificate or missed intermediate CA imports. Re-import intermediate(s) and the leaf to the alias with the private key. -
“This jar contains entries whose signer certificate is not yet valid or has expired”
Your system clock is wrong, or your Java code signing certificate is expired. If expired, re-sign with a new certificate; if timestamped, the signature should still validate. -
“Algorithm constraints check failed”
You used SHA-1 or another disallowed algorithm. Re-sign using SHA-256 and modern key sizes. -
“No TSA server certificate chain received”
The timestamp server was unavailable or blocked. Try again or switch to another TSA URL from your CA.
Verification beyond jarsigner: independent checks
For regulated environments or audits, you may want additional verification beyond jarsigner:
-
Extract and inspect
META-INFentries to confirm signature files exist and reference correct digests. -
Use third-party verification tools or antivirus suites that validate Authenticode-like metadata.
-
Maintain a release ledger: artifact hash, signing alias, certificate serial number, TSA URL, and build ID.
Documenting these details creates traceability for your signed Java applications and simplifies incident response in case of a revoked or replaced code signing certificate.
Practical distribution considerations
After signing, avoid modifying the JAR. Repacking, re-zipping, or adding files after signing invalidates the signature. If you must change content, rebuild and re-sign. For multi-module applications, sign each distributable JAR. If you ship native launchers that wrap your Java app, consider platform-specific signing for those binaries as well.
Where possible, publish checksums (SHA-256) alongside downloads and keep your timestamped signatures intact. Enterprise customers often validate both the checksum and the Java signature before deploying to managed systems.
How to Verify a Signed Java Application
Verifying a signed Java application is just as important as signing it. A proper verification step confirms that your Java code signing certificate was embedded correctly, the certificate chain is intact, the digest and signature algorithms satisfy modern JVM constraints, and the timestamp proves the JAR was signed while the certificate was valid. Skipping verification risks distributing artifacts that fail on customer machines due to missing intermediates, weak algorithms, or corrupted signatures. In this section we will validate with jarsigner, inspect the certificate chain, check timestamping, and outline additional runtime and programmatic verification approaches that strengthen your release process.
Verification has three pillars. First, structural integrity: the archive’s entries must match the digests recorded in the signature files under META-INF/. Second, trust chain correctness: the leaf certificate used to sign must chain to trusted intermediate CA certificates and a root in a truststore recognized by the client’s JVM or operating system. Third, temporal validity: either the code signing certificate is still valid at verification time, or a TSA timestamp asserts that the signature was created when the certificate was valid. When these conditions hold, your signed JAR will execute with the expected publisher identity and without spurious warnings.
Verify with jarsigner (structural, chain, and timestamp checks)
The canonical check uses jarsigner -verify. Start with a verbose pass that prints the signer’s certificate chain and entry-by-entry digest validation.
A successful run ends with jar verified. and lists each file’s digest as sm (signed and matched). The -certs flag prints the certificate chain after each signed entry; use it to confirm that the leaf certificate, intermediate CA(s), and issuer names align with what your Java code signing certificate provider issued. If you imported the chain correctly during setup, the alias in your keystore produced a PrivateKeyEntry with that same chain; this is your first indication that the right alias and chain were used during signing.
For stricter enforcement of algorithm constraints and signature hygiene, add -strict. This causes verification to fail when legacy algorithms (for example, SHA-1) or malformed metadata are detected:
If you see warnings such as “The signer certificate is self-signed” or “This jar contains entries whose certificate chain is not validated,” revisit your keystore: you likely imported only the leaf certificate to the signing alias without the intermediate(s), or you signed from a keystore that doesn’t hold the private key and full chain at the same alias.
Confirm timestamping and long-term validity
Timestamping is what preserves trust after the code signing certificate expires. When you signed with -tsa <URL>, jarsigner embedded an RFC 3161 timestamp token alongside the signature. To confirm its presence, search the verbose output for a line similar to Signed by "CN=..."; TSA: ... or a block indicating a timestamp certificate chain.
A practical test is to check verification on a machine whose system time is advanced beyond the certificate’s not-after date (in a controlled environment). A properly timestamped JAR still verifies, because the timestamp demonstrates the signature was created during the certificate’s validity window. Without timestamping, the same JAR fails verification once the signing certificate expires, forcing you to re-sign or re-ship.
Inspect the signature files in META-INF
If you need to diagnose signature integrity issues, inspect the archive:
You should find:
-
A signature file
META-INF/<ALIAS>.SFthat lists digests for each entry -
A signature block
META-INF/<ALIAS>.RSA(or.DSA/.EC) that contains the CMS/PKCS#7 signature and, typically, the embedded certificate chain
Extract these files and review their contents. The .SF file’s digests must correspond to the actual bytes of each entry; any post-signing modification (even changing a manifest attribute) invalidates the signature. This is why build pipelines should finalize the JAR content before signing and avoid repacking after.
Validate the certificate chain outside the JAR
Even if jarsigner passes, enterprises often require an independent check of the Java code signing certificate and its chain. Use keytool or openssl to print details and confirm serial numbers, validity windows, and issuers.
From the keystore you used to sign:
Verify that:
-
Entry typeisPrivateKeyEntry -
The first certificate in the chain is your leaf (Publisher)
-
Subsequent certificates are your intermediate CA(s)
-
Algorithms read as
SHA256withRSA(or stronger)
If you need to inspect the certificate embedded in the JAR’s signature block, you can extract it with jarsigner -verify -verbose -certs output or use tools that parse the PKCS#7 inside META-INF/*.RSA.
Cross-validate with the runtime truststore (JVM and OS)
Java verification relies on truststores. On many systems, the JVM consults the bundled cacerts truststore; some distributions can also defer to the operating system’s root store. A signature chain that verifies on your build host might fail at a customer site if their truststore is outdated or lacks a required intermediate. To reduce surprises:
-
Test verification on the target JVM versions your customers use.
-
If you support legacy JVMs, ensure your intermediate CA uses algorithms those JVMs accept.
-
Keep your build and test machines patched so you don’t sign against deprecated chains.
Where feasible, validate on multiple platforms (Windows, macOS, Linux) to detect platform-specific trust anomalies before release.
Programmatic verification for CI/CD and acceptance gates
Beyond manual jarsigner runs, strong pipelines enforce verification automatically. You can implement a “signature gate” stage that fails a build when any of the following conditions occur:
-
No signature present
-
Chain missing intermediates
-
Disallowed signature or digest algorithm (e.g., SHA-1)
-
No timestamp token present
-
Signer certificate expired and no timestamp present
-
Signer CN or serial number doesn’t match an allow-list
You can script this gate with jarsigner -verify -verbose -strict and parse its output, or use Java’s java.security APIs to load and validate the JarFile, the JarEntry digests, and the signer certificates programmatically. Capturing signer certificate serial numbers and TSA URLs as build metadata helps audit releases and accelerates incident response if a code signing certificate must be revoked and rotated.
Troubleshooting verification failures (targeted remedies)
When verification fails, the error message usually points to the underlying cause. Use these focused remedies:
-
Chain not validated or unknown issuer
Import the intermediate CA certificates into the signing keystore and re-sign. Confirm the alias holding the private key also holds the leaf plus intermediates. -
Weak or disallowed algorithms
Re-sign using-digestalg SHA-256 -sigalg SHA256withRSA(or appropriate EC). Ensure your keystore’s key size is at least RSA-2048 or RSA-3072. -
Signature valid but considered expired
Re-sign with-tsa <URL>so the timestamp token preserves validity after certificate expiry. -
Multiple signatures conflict or entries modified
Rebuild the JAR, ensure content is finalized, and sign once per release with a single Java code signing certificate alias. Do not alter the archive post-signing. -
“jar is unsigned” on some clients, verified on others
Check client JVM truststores and corporate SSL inspection devices. Outdated truststores or SSL interception can prevent proper chain validation.
These checks bring your verification routine in line with enterprise requirements and reduce false negatives during customer deployment.
Release readiness checklist (verification essentials)
Before distributing a signed Java application, confirm the following:
-
The JAR verifies cleanly with
jarsigner -verify -verbose -certs -strict -
The Java code signing certificate chain shows the expected leaf and intermediate CA(s)
-
The signature includes a valid RFC 3161 timestamp from a reliable TSA
-
Algorithms comply with your target JVMs’ security policies (SHA-256+)
-
Build metadata captures signer certificate serial number and TSA URL
-
The artifact is immutable after signing (no repacking or byte changes)
Embedding this checklist in your CI/CD “verify” stage ensures that every release passes the same objective standards, preventing last-minute surprises in production.
Troubleshooting Common Java Code Signing Errors
Even with a correctly issued Java code signing certificate and a careful keytool/jarsigner workflow, issues can surface during signing, verification, or runtime. Successful troubleshooting starts with understanding what each message means, then applying a targeted fix that preserves security properties (authenticity, integrity, and long-term validity via timestamping). This section consolidates the most frequent failures you’ll encounter when signing Java applications and JAR files, explains why they occur, and provides precise, reproducible remedies using keytool, jarsigner, and—when needed—OpenSSL or PKCS#11 middleware. Guidance is applicable to both standard and EV Java code signing certificates, JKS and PKCS12 keystores, and build pipelines using Maven or Gradle.
A recurring theme in Java code signing troubleshooting is the relationship between your private key, the certificate chain, and the keystore alias. The alias that holds the private key must end up with a PrivateKeyEntry containing the leaf certificate and the intermediate CA certificates; otherwise jarsigner cannot produce a signature that clients trust. Another common thread is algorithm policy: modern JVMs block SHA-1 and other weak primitives, so signatures must use SHA-256 or stronger. Finally, remember that timestamping is not optional in production: it is the mechanism that keeps a valid signature trusted after your Java code signing certificate expires.
“Keystore was tampered with, or password was incorrect”
This error appears when jarsigner or keytool cannot decrypt the keystore or the selected entry. Most often the keystore password or key password is wrong, you are pointing at the wrong file, or the keystore is corrupt.
Root causes:
-
Wrong
-storepassor-keypass -
Accidentally using the JRE toolchain instead of the JDK (path confusion)
-
File corruption (e.g., truncated PKCS12)
-
Mixing up keystores between CSR creation and import
Immediate fixes:
-
Verify which
keytool/jarsigneryou are invoking:which jarsignerand ensure it’s from the JDK you expect. -
List entries to confirm readability:
-
If corrupt, restore the keystore from backup; if you lack backup, you must re-issue the Java code signing certificate (keys cannot be recovered).
“No certificate from a trusted CA” / “Chain not validated”
jarsigner -verify may report that the signer’s chain cannot be validated. This typically means you imported only the leaf certificate to the signing alias, but not the intermediate CA certificates.
Root causes:
-
Missing intermediate CA(s) in the keystore
-
Imported the leaf certificate to a different alias than the private key
-
Using an outdated client truststore that lacks necessary intermediates
Immediate fixes:
-
Import intermediates first (unique aliases), then import the leaf to the alias that holds the private key:
-
Confirm the entry type:
It must say
Entry type: PrivateKeyEntryand show a chain: leaf → intermediate(s). -
Test verification with strict mode:
“Entry type is trustedCertEntry” (no private key available)
When listing the alias, Entry type: trustedCertEntry means you imported certificates into an alias that does not hold a private key. jarsigner needs a PrivateKeyEntry.
Root causes:
-
Created the CSR on one keystore, imported the issued certs into a different keystore
-
Imported the leaf to a new alias (not the CSR alias)
Immediate fixes:
-
Re-import the leaf certificate to the same alias that holds the private key created during CSR generation (e.g.,
codesign). -
If you no longer have the keystore with the private key, you must generate a new key pair and request a reissue from your CA.
“Algorithm constraints check failed” / SHA-1 rejected
Modern JVM security policies reject weak algorithms. If your signature or certificate chain uses SHA-1 or too-small keys, verification fails.
Root causes:
-
Using
-digestalg SHA1or defaulting to SHA-1 on very old tooling -
Legacy intermediate CA with weak signature
-
RSA key size below 2048 bits
Immediate fixes:
-
Re-sign with modern algorithms:
-
Ensure your keystore key is RSA-2048 or RSA-3072 (or a supported EC key).
-
If the CA chain itself is weak and clients reject it, contact the CA for re-issuance on a modern chain.
“This jar contains entries whose signer certificate is not yet valid or has expired”
This indicates a time validity problem, either with the system clock or the certificate. If the certificate expired and you did not timestamp the signature, clients may reject it.
Root causes:
-
System clock incorrect on the verification machine
-
Signing certificate expired and no timestamp token is present
-
Timestamp token present but invalid or unreachable CA chain for TSA
Immediate fixes:
-
Correct the system clock and re-verify.
-
Always sign with a TSA:
-
If the cert is expired but you timestamped at signing time, verification should still pass. If not, inspect the verbose output to confirm a valid TSA token is embedded.
“JAR is unsigned” or signature invalid after repacking
Any modification to a signed JAR—adding a file, altering the manifest, or repacking—breaks the signature.
Root causes:
-
Build step modifies artifacts post-sign
-
A zip step recompresses or reorders entries after signing
Immediate fixes:
-
Ensure signing is the final step that touches the artifact’s bytes.
-
If content must change, rebuild and re-sign. Do not attempt to hand-edit
META-INF/*signature files.
EV token / HSM not accessible (PKCS#11 issues)
When using an EV Java code signing certificate backed by a USB token or HSM, jarsigner needs access via the vendor’s PKCS#11 module.
Root causes:
-
PKCS#11 driver not installed or wrong library path
-
Token locked (PIN retries exceeded) or not initialized
-
CI runners without hardware access
Immediate fixes:
-
Install vendor middleware and note the module path, then configure a PKCS#11 provider (example snippet varies by JDK/vendor).
-
Test listing the token:
-
For CI/CD, consider a network HSM with secure lanes rather than a USB token physically attached to the runner.
“No TSA server certificate chain received” / timestamp failures
Timestamping can fail if the TSA URL is down, blocked by a proxy, or if there’s TLS inspection.
Root causes:
-
TSA endpoint outage or proxy block
-
Corporate firewall requires proxy configuration for outbound requests
-
Stale or incorrect TSA URL
Immediate fixes:
-
Retry with a different TSA provided by your CA:
-
If behind a corporate proxy, configure proxy variables or run signing on a host with allowed egress.
“PKCS12 not found or cannot be parsed”
keytool and jarsigner accept PKCS#12, but corrupted files or incorrect conversions cause parse errors.
Root causes:
-
Partial download of
.pfxor.p12 -
DER/Base64 confusion during conversion
-
Password mismatch
Immediate fixes:
-
Validate the container with OpenSSL:
-
Re-export from the source or re-download from the CA portal.
-
If converting to JKS:
“PKIX path building failed” (client-side verification)
While more common with TLS, some environments report this when validating JAR signatures if the client lacks intermediates or has an outdated truststore.
Root causes:
-
Client JVM missing intermediate CA(s) in its trust anchors
-
Corporate SSL inspection interfering with validation
Immediate fixes:
-
Ensure you signed with a full chain in the keystore (leaf + intermediates).
-
Update the client JVM’s truststore to current CA roots/intermediates (or update the JVM itself).
-
Verify with:
Manifest or digest mismatches after build
Reproducibility matters: differences in file order, timestamps, or line endings can cause digest mismatches between builds.
Root causes:
-
Non-deterministic build process changing archive metadata
-
Post-processing steps that touch MANIFEST.MF
Immediate fixes:
-
Standardize build tooling and enable reproducible archives where available.
-
Generate the final JAR deterministically, then sign it—and do not touch it afterward.
Quick diagnostic checklist (when time is tight)
Use this abbreviated sequence to localize most Java code signing certificate issues quickly:
-
List the signing alias and confirm
PrivateKeyEntryand full chain: -
Verify the JAR strictly:
-
Re-sign with explicit modern algorithms and TSA:
-
If using EV, validate PKCS#11 access to the token and confirm PIN and module path.
-
If all else fails, rebuild the artifact, import intermediates correctly, and sign again from a clean environment.
Updating or Renewing Java Code Signing Certificates
Every Java code signing certificate has a finite validity period. When it nears expiration—or if you must rotate keys for security—you need a renewal or reissue plan that preserves trust for already shipped Java applications and ensures new releases continue to verify cleanly. The core objective is simple: avoid any gap in signing capability and ensure previously signed JAR files remain valid by virtue of RFC 3161 timestamping. This section explains what “renewal” actually means in PKI terms, how to handle keystores and aliases during rotation, and how to keep CI/CD pipelines running while you transition to a new Java code signing certificate.
From a public key infrastructure perspective, a “renewal” from your Certificate Authority generally creates a new leaf certificate with new validity dates and often a different serial number—and best practice is to use a new private key as well. Treat renewal as a mini-migration: you will end with two Signing Identities for a time—the expiring one (used only to validate previously signed artifacts) and the new one (used to sign new releases). Because you timestamped past releases, they remain trusted even after the old certificate’s not-after date.
When to start the renewal process
Begin renewal 30–45 days before the Java code signing certificate expires. This allows time for CA validation, internal approvals, and testing. If you use an EV Java code signing certificate backed by a USB token or HSM, budget additional time to provision hardware, drivers, and PKCS#11 middleware.
Renewal vs reissue vs key rotation
-
Renewal: Obtain a new certificate for the same organization. Best practice is to generate a fresh key pair and CSR in your keystore (or on your HSM), then import the newly issued certificate and intermediates to a new alias (for example,
codesign-2026). -
Reissue: The CA replaces a certificate during its active period (e.g., after organization name change or chain migration). You still import the new leaf and intermediates to the alias that holds the corresponding private key.
-
Key rotation: You deliberately replace the private key and certificate combination to reduce long-term key exposure. Rotation is recommended at least at each renewal.
Safe renewal workflow (minimize downtime)
-
Generate a new key pair and CSR in a separate keystore or alias. Keep the current alias untouched so CI/CD can continue signing until the new cert is live.
-
Submit the CSR to the CA; complete org validation and any EV steps.
-
Import intermediates and the new leaf into the new alias, forming a
PrivateKeyEntrywith a full chain. -
Test signing a staging JAR with the new alias and verify with
jarsigner -verify -verbose -certs -strict. Confirm timestamping with your TSA. -
Switch CI/CD to the new alias and keystore by toggling environment variables or a build parameter.
-
Archive the old keystore in a secure vault for audit/reproducibility. Do not delete it; old signatures may be needed for forensic validation.
-
Document the rotation: record certificate serial numbers, validity windows, TSA URLs used, and the build IDs marking the switchover.
Will I need to re-sign old releases?
If you timestamped when signing, you typically do not need to re-sign old artifacts. Timestamping proves the code was signed when the Java code signing certificate was valid. Re-sign only if a business requirement or revocation event demands it. If a certificate is revoked, timestamp does not rescue trust—plan an emergency re-sign with a safe certificate and communicate to customers.
Handling EV token and HSM renewals
For EV Java code signing certificates on tokens/HSMs, your CA may issue the new certificate bound to a new token. Validate driver versions, PKCS#11 module paths, and PIN policies. In CI/CD, favor network HSMs with audited access rather than attempting to pass USB tokens into ephemeral runners.
Common renewal pitfalls
-
Importing a renewed leaf into the wrong alias (one without the matching private key). Verify with
keytool -list -v -alias <alias>. -
Forgetting to update intermediate CA certificates; some renewals migrate you to a new intermediate chain.
-
Switching the build to the new certificate before timestamping/connectivity is validated; sign a staging JAR first.
-
Deleting the old keystore—retain it in a secure archive for audit and for validating legacy releases.
Best Practices for Java Code Signing
Strong Java code signing practices reduce warnings, prevent supply chain incidents, and make audits straightforward. Treat your Java code signing certificate as a production credential with controls comparable to SSH or cloud keys.
Protect private keys and keystores
Store keystores on encrypted volumes, restrict filesystem permissions, and never commit .jks, .p12, or .pfx files to source control. In CI/CD, mount keystores at runtime from a secure secret manager, inject passwords via short-lived environment variables, and limit job permissions to sign only the artifacts they build.
Prefer modern algorithms and key sizes
Use SHA256withRSA with at least RSA-2048 (ideally RSA-3072). Avoid SHA-1 and low-strength keys; JVM algorithm constraints will increasingly reject them. If you use EC, confirm CA and client JVM support for SHA256withECDSA.
Always timestamp releases
Pass -tsa with a reliable TSA URL on every jarsigner invocation. Timestamping ensures signatures remain valid after the certificate expires and enables clean audit trails.
Sign as the final immutable step
Finalize the JAR content, then sign. Any byte change after signing (repacking, manifest edits, resource injection) invalidates signatures. In multi-module builds, sign each distributable JAR and publish checksums.
Keep chains current and complete
Import intermediate CA certificates into the signing alias’s keystore entry before importing the leaf. Test verification on representative JVM versions and platforms to catch truststore differences early.
Automate in Maven/Gradle and gate with verification
Integrate signing in your build lifecycle and enforce a verification gate that fails builds when signatures, chains, algorithms, or timestamps are missing or weak. Capture signer serial numbers and TSA URLs as build metadata.
Rotate keys on renewal and document everything
At each renewal, generate new key material, create a new alias, and record the switch in a release ledger. Keep the old keystore in a secure archive for compliance.
Plan for incident response
If a Java code signing certificate or keystore is suspected compromised: revoke immediately, halt releases, rotate keys, re-issue, and re-sign affected artifacts. Maintain a tested runbook and contacts at your CA.
Conclusion
A robust Java code signing certificate program protects users and organizations from tampered software, impersonation, and supply-chain risk. The essentials are consistent: generate strong keys, maintain keystores securely, import complete certificate chains, sign JAR files with modern algorithms, and timestamp every release. Verification should be routine—both in development and CI/CD—so that problems surface before distribution. When it’s time to renew, rotate keys deliberately, test before flipping CI, and preserve auditability by documenting serial numbers, TSA details, and the build boundary where you switched to the new certificate.
By following the setup steps, signing procedures, verification checks, troubleshooting playbooks, and best practices outlined in this guide, you can deploy and maintain signed Java applications with high confidence. Your users will see verified publisher identities instead of “Unknown,” your releases will remain valid long after certificate expiry thanks to timestamping, and your engineering teams will have a predictable, auditable path for future renewals and incident response.
FAQs: Java Code Signing Certificate Set Up and Usage
Can I use Let’s Encrypt for Java code signing?
No. Let’s Encrypt issues TLS/SSL certificates for servers, not code signing certificates. For Java code signing, obtain a certificate from a CA that offers code signing (e.g., Sectigo, DigiCert, GlobalSign, SSL.com).
What happens if my Java code signing certificate expires?
New releases must be signed with a valid certificate. Previously signed JARs continue to verify if they were timestamped at signing time. Without a timestamp, signatures may be treated as invalid after expiry.
Do I need an EV Java code signing certificate?
EV provides stronger publisher validation and often requires hardware key storage (token or HSM). It’s recommended for enterprises and high-trust distributions. Standard certificates are sufficient for many independent developers.
How do I convert a PFX to a Java Keystore (JKS) for signing?
Use keytool -importkeystore to convert PKCS#12 (.pfx/.p12) to JKS. Ensure the resulting alias holds a PrivateKeyEntry with the full certificate chain.
Is it possible to sign JARs from CI/CD safely?
Yes. Store the keystore in a secret manager, mount at job runtime, inject passwords via secure variables, and restrict job permissions. Consider HSM-backed signing for higher assurance.
What does “Algorithm constraints check failed” mean when verifying?
The JVM rejected weak algorithms (e.g., SHA-1) or small keys. Re-sign using SHA-256 and at least RSA-2048, and ensure your CA chain is modern.
Do I need to re-sign after renewing my Java code signing certificate?
Only for new releases. Old releases remain trusted if they were timestamped. Re-signing historic artifacts is generally unnecessary unless there’s a revocation or policy change.
How do I verify a signed JAR?
Run jarsigner -verify -verbose -certs -strict <file.jar>. Look for “jar verified.” and ensure the printed certificate chain matches your issuer and intermediates.
Why does my signed JAR still show warnings on some machines?
The client JVM or OS truststore may be outdated, missing required intermediates, or subject to SSL inspection. Update the client environment and verify with strict mode.
Can I store the keystore in Git if it is encrypted?
Avoid it. Even encrypted blobs introduce risk. Prefer a dedicated secret vault with access controls and audit trails.
