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. Commands were run on Ubuntu with OpenJDK 25.
Tested on: Ubuntu 26.04 LTS; OpenJDK 25.0.3; kernel 7.0.0-27-generic.
Prerequisites
Install both tools and gather the PEM pair before you try any import — the fix depends on OpenSSL to bridge PEM into PKCS12.
keytoolandopensslonPATH. See Install keytool on Ubuntu if the command is missing.- PEM files: an X.509 certificate (
.crt,.cer,.pem) and matching private key (.key, often PKCS#8BEGIN 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:
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:
keytool -importcert -alias pem-wrong \
-file server.crt \
-keystore wrong.jks -storetype JKS \
-storepass changeit -nopromptCertificate was added to keystoreThat message is misleading on its own. List the keystore to see the actual entry type:
keytool -list -v -keystore wrong.jks -storetype JKS -storepass changeitAlias name: pem-wrong
Entry type: trustedCertEntrytrustedCertEntry 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.
.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:
keytool -importcert -alias bad-key \
-file server.key \
-keystore bad-key.jks \
-storepass changeit -nopromptkeytool error: java.lang.Exception: Input not an X.509 certificateA 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:
openssl x509 -in server.crt -noout -pubkey | openssl sha256
openssl pkey -in server.key -pubout | openssl sha256SHA2-256(stdin)= c14fb42f849f18f4c0e2839e671f117c4ca66b0f99dad99e33a81e264297dc2b
SHA2-256(stdin)= c14fb42f849f18f4c0e2839e671f117c4ca66b0f99dad99e33a81e264297dc2bThe 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:
openssl pkcs12 -export \
-inkey server.key \
-in server.crt \
-out server.p12 \
-name pem-right \
-passout pass:changeitUse 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:
keytool -list -v \
-keystore server.p12 \
-storetype PKCS12 \
-storepass changeit \
-alias pem-right | grep -E "Entry type|Certificate chain length|Owner:|Issuer:"Entry type: PrivateKeyEntry
Certificate chain length: 1
Owner: CN=lab.example.com
Issuer: CN=lab.example.comFor 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:
keytool -importkeystore \
-srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass changeit \
-destkeystore identity.p12 -deststoretype PKCS12 -deststorepass changeit \
-nopromptImporting keystore server.p12 to identity.p12...
Entry for alias pem-right successfully imported.
Import command completed: 1 entries successfully imported, 0 entries failed or cancelledIf an older application explicitly requires JKS, import into JKS instead:
keytool -importkeystore \
-srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass changeit \
-destkeystore correct.jks -deststoretype JKS -deststorepass changeit \
-nopromptImporting 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:
keytool -list -v -keystore identity.p12 -storetype PKCS12 -storepass changeitKeystore type: PKCS12
Alias name: pem-right
Entry type: PrivateKeyEntryPrivateKeyEntry 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:
keytool -list -v -keystore correct.jks -storetype JKS -storepass changeitKeystore type: JKS
Alias name: pem-right
Entry type: PrivateKeyEntrySee 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
- keytool — Java SE 25 documentation
- keytool(1) — Ubuntu man page
- JEP 229: Create PKCS12 Keystores by Default
- On-site: keytool cheat sheet, Install keytool on Ubuntu, Java keystore vs truststore, OpenSSL cheat sheet
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.

