Import PEM Certificate and Private Key into Java Keystore

Tested on Ubuntu 26.04 LTS
Package java-21-openjdk
Applies to Ubuntu, Debian, RHEL, Rocky Linux, AlmaLinux, Oracle Linux, CentOS Stream, Fedora
Privilege sudo or root
Scope Learn why creates trustedCertEntry instead of PrivateKeyEntry, then wrap cert and key.
Related guides keytool Tutorial
Install keytool on Ubuntu
List and inspect keystore entries
Export certificate in PEM and DER
Import PKCS12/PFX into Java keystore

You received a TLS certificate and private key as separate PEM files — server.crt and server.key — and need them inside a Java keystore for Tomcat, Spring Boot, or a custom SSLContext. keytool is the usual tool, but -importcert alone does not load a private key. Many teams import the certificate, see trustedCertEntry in keytool -list, and wonder why HTTPS still fails.

This guide shows the wrong paths (cert-only import, raw key import), the fix with openssl pkcs12 -export plus keytool -importkeystore, and how to verify a PrivateKeyEntry. The OpenSSL export step matches create PKCS12 from CRT and KEY. Commands were run on Ubuntu with OpenJDK 25.


Prerequisites

Install both tools and gather the PEM pair before you try any import — the fix depends on OpenSSL to bridge PEM into PKCS12.

  • keytool and openssl on PATH. See Install keytool on Ubuntu if the command is missing, and OpenSSL for pkcs12 -export and inspection commands.
  • PEM files: an X.509 certificate (.crt, .cer, .pem) and matching private key (.key, often PKCS#8 BEGIN PRIVATE KEY).
  • A destination keystore password you will configure in the application.

For entry-type background (PrivateKeyEntry vs trustedCertEntry), see Java keystore vs truststore.


Understand what keytool can import

keytool routes each input type to a different entry shape. Knowing which command accepts which format saves you from a successful import that still cannot serve HTTPS.

Input keytool command Result in keystore
X.509 certificate PEM/DER -importcert New alias: trustedCertEntry; existing key alias: certificate reply for PrivateKeyEntry
PEM private key only -importcert Error: not an X.509 certificate
PKCS12 / PFX (cert + key) -importkeystore or open as PKCS12 store PrivateKeyEntry
PEM cert + PEM key (two files) No single-step keytool import Use OpenSSL to build PKCS12 first

In this article, the “wrong approach” imports server.crt into a new alias, so keytool creates trustedCertEntry. That is different from importing a CA-signed reply onto an existing key alias created by -genkeypair — see Create a CSR with keytool and import a CA-signed certificate.

keytool manages keystores; it does not parse standalone PEM private keys. OpenSSL bridges PEM to PKCS12, which keytool understands.


Lab setup: create sample PEM files

The lab uses a self-signed pair under /tmp/keytool-lab. Adjust paths for your real certificate. One OpenSSL command creates both PEM files:

bash
mkdir -p /tmp/keytool-lab && cd /tmp/keytool-lab

openssl req -x509 -newkey rsa:2048 \
  -keyout server.key -out server.crt \
  -days 365 -nodes \
  -subj "/CN=lab.example.com"

Both files are PEM-encoded. server.crt is the public certificate; server.key is the private key Tomcat needs for HTTPS. You will import this pair in the steps below.


Wrong approach: import only the certificate PEM

A common mistake is importing server.crt with -importcert and assuming the private key is included. The command succeeds because the certificate is valid X.509 — it just does not attach the key.

Import the certificate alone:

bash
keytool -importcert -alias pem-wrong \
  -file server.crt \
  -keystore wrong.jks -storetype JKS \
  -storepass changeit -noprompt
text
Certificate was added to keystore

That message is misleading on its own. List the keystore to see the actual entry type:

bash
keytool -list -v -keystore wrong.jks -storetype JKS -storepass changeit
text
Alias name: pem-wrong
Entry type: trustedCertEntry

trustedCertEntry means public certificate only — suitable for a truststore or CA anchor, not for a Java server identity. Spring Boot server.ssl.key-store and Tomcat keystore settings such as certificateKeystoreFile / certificateKeyAlias need an alias that resolves to PrivateKeyEntry.

WARNING
If you only imported the .crt PEM, you do not have a private key in the keystore. HTTPS connectors will fail or fall back to the wrong entry.

Wrong approach: import the private key PEM with -importcert

-importcert validates X.509 structure only. Feeding it a PEM private key fails immediately:

bash
keytool -importcert -alias bad-key \
  -file server.key \
  -keystore bad-key.jks \
  -storepass changeit -noprompt
text
keytool error: java.lang.Exception: Input not an X.509 certificate

A PEM private key is not a certificate, so there is no keytool flag that imports it directly. Build PKCS12 with OpenSSL first.


Correct approach: OpenSSL PKCS12, then keytool importkeystore

The reliable path wraps cert and key into PKCS12, then copies the entry into your Java keystore with -importkeystore.

Step 1 — Verify the PEM pair and build PKCS12

Confirm the certificate and private key belong together before you bundle them:

bash
openssl x509 -in server.crt -noout -pubkey | openssl sha256
openssl pkey -in server.key -pubout | openssl sha256
text
SHA2-256(stdin)= c14fb42f849f18f4c0e2839e671f117c4ca66b0f99dad99e33a81e264297dc2b
SHA2-256(stdin)= c14fb42f849f18f4c0e2839e671f117c4ca66b0f99dad99e33a81e264297dc2b

The hashes should match. If they do not, the certificate and private key are not a pair.

Combine the PEM pair into a single PKCS12 bundle. The -name flag sets the alias inside the bundle:

bash
openssl pkcs12 -export \
  -inkey server.key \
  -in server.crt \
  -out server.p12 \
  -name pem-right \
  -passout pass:changeit

Use the same alias in Tomcat or Spring Boot if you keep pem-right. If you have a certificate chain, add -certfile ca-bundle.crt so intermediates ship with the identity.

Verify the PKCS12 bundle before importing into another keystore:

bash
keytool -list -v \
  -keystore server.p12 \
  -storetype PKCS12 \
  -storepass changeit \
  -alias pem-right | grep -E "Entry type|Certificate chain length|Owner:|Issuer:"
text
Entry type: PrivateKeyEntry
Certificate chain length: 1
Owner: CN=lab.example.com
Issuer: CN=lab.example.com

For this self-signed lab, chain length is 1. If you included a CA bundle with -certfile ca-bundle.crt, the chain length should be greater than 1.

Step 2 — Use the PKCS12 directly or import into another PKCS12 keystore

Spring Boot and Tomcat accept PKCS12 natively (OpenJDK 9+ default per JEP 229). You can deploy server.p12 from Step 1 as-is, or copy it into a dedicated identity file:

bash
keytool -importkeystore \
  -srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass changeit \
  -destkeystore identity.p12 -deststoretype PKCS12 -deststorepass changeit \
  -noprompt
text
Importing keystore server.p12 to identity.p12...
Entry for alias pem-right successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled

If an older application explicitly requires JKS, import into JKS instead:

bash
keytool -importkeystore \
  -srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass changeit \
  -destkeystore correct.jks -deststoretype JKS -deststorepass changeit \
  -noprompt
text
Importing keystore server.p12 to correct.jks...
Entry for alias pem-right successfully imported.
Import command completed:  1 entries successfully imported, 0 entries failed or cancelled

Warning:
The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format using "keytool -importkeystore -srckeystore correct.jks -destkeystore correct.jks -deststoretype pkcs12".

Step 3 — Verify PrivateKeyEntry

List the PKCS12 destination and confirm the alias shows PrivateKeyEntry, not trustedCertEntry:

bash
keytool -list -v -keystore identity.p12 -storetype PKCS12 -storepass changeit
text
Keystore type: PKCS12
Alias name: pem-right
Entry type: PrivateKeyEntry

PrivateKeyEntry confirms both the private key and certificate chain are present. Point your app at identity.p12 (or server.p12) with alias pem-right and server.ssl.key-store-type=PKCS12.

For the legacy JKS path, the same alias should also report PrivateKeyEntry:

bash
keytool -list -v -keystore correct.jks -storetype JKS -storepass changeit
text
Keystore type: JKS
Alias name: pem-right
Entry type: PrivateKeyEntry

See Import PKCS12/PFX into Java keystore when the file is already .p12 or .pfx from a vendor.


Troubleshooting

Use this table when import succeeds but HTTPS still fails or OpenSSL reports a key mismatch:

Symptom Likely cause Fix
trustedCertEntry after import Only certificate PEM was imported Rebuild PKCS12 with -inkey and use -importkeystore
Input not an X.509 certificate Private key passed to -importcert Use openssl pkcs12 -export instead
openssl pkcs12 asks for pass phrase Encrypted private key Add -passin pass:YOUR_KEY_PASS
Alias mismatch in Tomcat -name in openssl ≠ configured alias Match alias in keytool -list and server config
unable to load private key Wrong key for certificate Regenerate bundle with matching pair

References


Summary

keytool -importcert imports public certificates as trustedCertEntry when you use a new alias — it never attaches a PEM private key. Importing only server.crt looks successful until you list the store and see no PrivateKeyEntry. The reliable path is openssl pkcs12 -export with -inkey and -in, then keytool -importkeystore into PKCS12 (identity.p12 or server.p12 directly). Use JKS only when legacy config requires it. Confirm with keytool -list -v before wiring the file into Tomcat or Spring Boot.


Frequently Asked Questions

1. Can keytool import a PEM private key directly?

No. keytool -importcert accepts X.509 certificates only. A PEM private key file produces Input not an X.509 certificate. Wrap the cert and key into PKCS12 with openssl pkcs12 -export, then run keytool -importkeystore to get a PrivateKeyEntry.

2. Why does my PEM import show trustedCertEntry instead of PrivateKeyEntry?

keytool -importcert stores public certificates without private keys as trustedCertEntry. Importing only server.crt from a PEM pair imports the cert but not the key, so Tomcat or Spring Boot cannot use the alias for HTTPS. You need a PKCS12 bundle that includes both parts.

3. What is the correct way to import PEM into a Java keystore?

Run openssl pkcs12 -export -inkey private.key -in certificate.crt -out bundle.p12, then keytool -importkeystore -srckeystore bundle.p12 -srcstoretype PKCS12 -destkeystore identity.p12 -deststoretype PKCS12. List with keytool -list -v and confirm Entry type: PrivateKeyEntry.

4. Should I use JKS or PKCS12 for the destination keystore?

Use PKCS12 (.p12) on OpenJDK 9 and later — it is the default keystore type since JEP 229. JKS still works but prints a proprietary-format warning. Spring Boot and Tomcat accept PKCS12 natively.

5. How do I import a PEM file that contains both cert and key in one file?

If the file is cert followed by key in PEM format, point openssl pkcs12 -export at the cert with -in and the key with -inkey (same path if combined). Then import the resulting .p12 with keytool -importkeystore. keytool still cannot read the combined PEM directly.
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with more than 15 years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)