How-to guide · Create keys and CSRs
How to create a CSR with Java keytool
In one sentence
You will have a key pair in a PKCS #12 keystore, a CSR whose SAN list really reaches the CA, and the signed certificate chain installed under the same alias.
- Platforms
- Java
- Level
- Practitioner · 6 steps
On this page
Before you start
- A JDK with
keytoolon the path (keytool -helpshould work). The commands below were run with OpenJDK 21. - Every name the certificate must cover, and any IP addresses clients use to connect.
- A place for the keystore on the server that will use it, readable only by the service account.
A keystore holds your private key and, later, its certificate chain under one alias. The private key never leaves it: you send the CA only the CSR.
Steps
1. Create the key pair in a new keystore
keytool -genkeypair -alias shop -keyalg EC -groupname secp256r1 \
-dname "CN=shop.example.com, O=Example Shop, C=BE" \
-ext "SAN=dns:shop.example.com,dns:www.shop.example.com" \
-storetype PKCS12 -keystore shop.p12
Generating 256 bit EC (secp256r1) key pair and self-signed certificate (SHA384withECDSA) with a validity of 90 days
for: CN=shop.example.com, O=Example Shop, C=BE
-keyalg EC -groupname secp256r1creates a P-256 key. For RSA, use-keyalg RSA -keysize 3072.- keytool asks for a keystore password. In a PKCS #12 keystore, the key uses the same password.
-storetype PKCS12is the default since JDK 9; it matters on JDK 8, whose default is the older JKS format.- The self-signed certificate is only a placeholder. The CA’s reply replaces it in step 6.
2. Create the CSR, and repeat the names
keytool -certreq -alias shop -keystore shop.p12 -file shop.csr \
-ext "SAN=dns:shop.example.com,dns:www.shop.example.com"
For clients that connect by IP address, add ip:192.0.2.10 to the list.
3. Check the CSR
keytool -printcertreq -file shop.csr
PKCS #10 Certificate Request (Version 1.0)
Subject: CN=shop.example.com, O=Example Shop, C=BE
Format: X.509
Public Key: 256-bit EC (secp256r1) key
Signature algorithm: SHA384withECDSA
Extension Request:
#1: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
DNSName: shop.example.com
DNSName: www.shop.example.com
]
Every name must appear under SubjectAlternativeName. You can also paste the CSR into the decoder under “Check it worked”.
4. Send the CSR to the CA
Submit shop.csr through your CA’s form or your internal PKI process. Ask for the reply as a chain: your certificate followed by the intermediates, as a PEM bundle or a .p7b file. If you receive separate files, join them, your certificate first:
cat shop.crt issuing-ca.crt > shop-chain.pem
5. Make sure keytool can trust the chain
keytool imports a reply only if it can build a chain to a root it trusts, either in your keystore or in the JDK’s trust store, a keystore file named cacerts in JAVA_HOME/lib/security.
- Public CA: its root is already in
cacerts. Add-trustcacertsin step 6. - Private CA: import its root into your keystore as a trusted entry first. Compare the fingerprint keytool shows with the one your PKI team publishes, and answer
yesonly if they match:
keytool -importcert -alias keystone-root -file root.crt -keystore shop.p12
Owner: CN=Keystone Demo Root CA, O=Keystone Demo, C=BE
...
SHA256: FE:F0:F5:E6:B9:C0:7B:2E:53:F6:D3:8B:0B:33:CD:0E:EA:81:C0:0D:B8:8D:50:38:88:0E:4E:D6:80:BE:5D:63
...
Trust this certificate? [no]: yes
Certificate was added to keystore
6. Import the reply into the same alias
Use the same alias as the key pair, so keytool replaces the placeholder:
keytool -importcert -alias shop -file shop-chain.pem -keystore shop.p12
Certificate reply was installed in keystore
For a public CA, add -trustcacerts. keytool also checks that the public key in the reply matches your private key, and refuses it otherwise.
Check it worked
keytool -list -v -alias shop -keystore shop.p12
Alias name: shop
Entry type: PrivateKeyEntry
Certificate chain length: 3
Certificate[1]:
Owner: CN=shop.example.com, O=Example Shop, C=BE
Issuer: CN=Keystone Demo Issuing CA 1, O=Keystone Demo, C=BE
...
Certificate[2]:
Owner: CN=Keystone Demo Issuing CA 1, O=Keystone Demo, C=BE
Issuer: CN=Keystone Demo Root CA, O=Keystone Demo, C=BE
...
Certificate[3]:
Owner: CN=Keystone Demo Root CA, O=Keystone Demo, C=BE
Issuer: CN=Keystone Demo Root CA, O=Keystone Demo, C=BE
Look for PrivateKeyEntry, a chain length of 2 or more, and your names under SubjectAlternativeName. A chain length of 1 with your own name as the issuer means the self-signed placeholder is still there. Paste the CSR here to double-check what you asked for:
Then point your server at the keystore: How to install a certificate in Tomcat and other Java servers.
If something goes wrong
- The issued certificate lacks your names:
-ext SAN=…was missing from-certreq(step 2). Create a new CSR from the same key and ask for a reissue. keytool error: java.lang.Exception: Failed to establish chain from reply: you imported only your certificate, and keytool cannot find its issuer. Import the chain file instead (step 4), and the private root if there is one (step 5).… is not trusted. Install reply anyway? [no]:: the chain ends at a root keytool does not know. Answerno, check the root’s fingerprint with your PKI team, import it (step 5) and try again.keytool error: java.lang.Exception: Public keys in reply and keystore don't match: the reply belongs to another key: the wrong alias, the wrong keystore, or a CSR from an earlier attempt. See How to check that a private key matches a certificate.- A warning that “The JKS keystore uses a proprietary format”: you created a JKS keystore. Move it to PKCS #12 with How to convert a Java keystore (JKS) to PKCS #12.
- Clients fail with
PKIX path building failed: the server sends an incomplete chain, or clients do not trust your private root. Check the chain length above, and the chain the server sends. - Clients connecting by IP get
No subject alternative names matching IP address … found: addip:entries to the SAN in step 2.
Why this works
The CSR is a PKCS #10 request, RFC 2986 (PKCS #10), signed with the key in your keystore to prove you hold it. keytool keeps that key under one alias, first with a self-signed placeholder and then, after the import, with the chain the CA returned. Because keytool insists on a chain to a trusted root and on matching public keys, a successful import already proves most of what can go wrong. Asking for a certificate explains the CSR, Who do we trust? explains cacerts and private roots, and the file formats appendix explains JKS and PKCS #12.
Go deeper
- Oracle: keytool (Java SE 21):
-genkeypair,-certreq,-extand how a certificate reply is imported. - RFC 2986: the PKCS #10 request format.
- RFC 7292: PKCS #12, the keystore format.
- RFC 5280, section 4.2.1.6: the Subject Alternative Name extension.
Early edition. Checked against the standards; an independent expert review is in progress. Found a mistake? Tell us.