read

Signing a JAR file is not just a way to make a warning disappear. It attaches an identity to the archive so consumers can verify who signed it and whether the signed content has changed.

The basic workflow is:

  1. Install a JDK so keytool and jarsigner are available.
  2. Import an existing code-signing certificate into a keystore.
  3. Identify the alias for the signing key.
  4. Sign the JAR.
  5. Timestamp the signature.
  6. Verify the result.

Oracle’s tool references are the source of truth for keytool and jarsigner behaviour:

Install the JDK

Install a current supported JDK, then open a terminal in the JDK bin directory or add it to PATH.

For example:

cd "C:\Program Files\Java\jdk-14.0.1\bin"

Use whatever JDK version is appropriate for your environment. The commands below are the important part, not the exact path.

Import the certificate

If your existing signing certificate is in a .p12 or .pfx file, import it into a keystore:

keytool -importkeystore `
    -srckeystore c:\jarfiles\duff.p12 `
    -srcstoretype PKCS12 `
    -destkeystore c:\jarfiles\duff.p12 `
    -deststoretype PKCS12

Older examples often convert into JKS first, then migrate to PKCS12 after keytool warns that JKS is proprietary. For new work, prefer PKCS12 unless you have a specific compatibility reason not to.

If you already have a working PKCS12 keystore, you may not need this conversion step at all.

Find the alias

List the keystore contents:

keytool -list -keystore c:\jarfiles\duff.p12 -storetype PKCS12 -v

Find the alias for the private key entry. You need that alias when signing. In my old example, the alias was similar to codesigningcert.

Sign the JAR

Sign the JAR and include a timestamp authority:

jarsigner `
    -keystore c:\jarfiles\duff.p12 `
    -storetype PKCS12 `
    -tsa http://timestamp.digicert.com `
    c:\jarfiles\myjar.jar `
    codesigningcert

The timestamp matters. Without a timestamp, the signature may stop validating cleanly after the signing certificate expires. With a trusted timestamp, verifiers can evaluate whether the certificate was valid at signing time.

Avoid putting keystore passwords directly into shell history. If you need automation, use your CI/CD secret store or a dedicated signing system rather than scattering signing credentials around build scripts.

Verify the signature

Verify the JAR:

jarsigner -verify c:\jarfiles\myjar.jar -verbose -certs -strict

Use -strict so warnings are treated seriously. Read the output rather than only checking that the command completed. You care about:

  • Whether the JAR verifies.
  • Whether the certificate chain is trusted by the verifier.
  • Whether the signature includes a timestamp.
  • Whether there are unsigned entries you did not expect.
  • Whether weak algorithms or expired certificates are reported.

Practical cautions

A signed JAR proves that the holder of the signing key signed that content. It does not prove the code is safe, bug-free, or approved for every environment.

Operationally, the signing key is the sensitive asset:

  • Store it in a proper secret-management or signing system.
  • Limit who can request signatures.
  • Log signing events.
  • Rotate and revoke certificates when needed.
  • Keep timestamping enabled.
  • Verify artifacts as part of release validation.

The happy path is short, but the trust model deserves respect. Code signing is only useful when the key is protected and the verification process actually checks the result.

References

Blog Logo

Chad Duffey


Published

Image

Chad Duffey

Blue Team -> Exploit Development & things in-between

Back to Overview