The keytool utility shipped with the Java Development Kit (JDK) creates a key pair inside a Java keystore and turns it into a CSR (Certificate Signing Request), the encoded block a Certificate Authority (CA) reads to identify you before it issues a certificate. For code signing, what keytool may legitimately be used for changed on June 1, 2023. This guide states the rule first, then walks through the keytool commands that are still correct: against a software keystore for internal signing, and against a hardware token or HSM through PKCS#11.
Code signing keys must be generated on hardware
Since June 1, 2023, the CA/Browser Forum Code Signing Baseline Requirements have required the private key for every publicly trusted code signing certificate to be generated and stored in a hardware crypto module that meets FIPS 140-2 Level 2, Common Criteria EAL4+, or an equivalent standard. The key must be non-exportable. This applies to standard (Organization Validation) certificates as well as Extended Validation ones. EV code signing always required hardware; the 2023 change extended the same rule to standard certificates. The same requirements set a minimum key size of RSA 3072 for code signing certificates, in force since June 1, 2021.
The consequence for this page is direct. A keystore file that keytool creates on your laptop or server, whether it is PKCS12 or the older JKS format, holds a software key. A CSR generated from it is not accepted by a public Certificate Authority for a code signing certificate. Certificate Authorities have stopped supporting browser-based key generation and downloadable key files for these products. Your key now originates in one of two places:
- A pre-configured token the CA ships to you. The CA generates the key pair and the CSR on a certified USB token on its side, loads the issued certificate onto it, and mails you the token. There is no CSR for you to create.
- Your own HSM or token, with key attestation. You generate the key inside the device, produce a CSR from it, and submit an attestation file that proves to the CA the key was created on compliant hardware and cannot be exported. Both parts are required; a CSR without valid attestation is rejected.
Which route applies is decided when you order. For the comparison, see the code signing certificate delivery methods. If you already own compliant hardware, follow the guide for your device: YubiKey 5 FIPS CSR generation and attestation or the Luna Network Attached HSM v7.x CSR and attestation guide.
Where keytool still fits
None of the above retires keytool. It remains the right tool in three situations, and only the first one produces a CSR you can send to a public CA:
- As a PKCS#11 front end to your token or HSM. keytool speaks PKCS#11 natively. Point it at your vendor’s PKCS#11 library and the key never leaves the device, while the familiar -certreq command still produces the CSR. The commands are in the hardware section below.
- For internal or enterprise signing. If you sign in-house software with your organization’s own CA, your internal policy governs key storage, not the public Baseline Requirements. A software keystore is a normal choice there.
- For rehearsal. Getting the subject name right on the first attempt is easier if you have run the prompts once against a throwaway keystore.
One limit worth knowing before you start: keytool does not generate key attestation. Attestation is produced by the token or HSM vendor’s own tooling, so even on the PKCS#11 path you will use the vendor utility for that file and keytool only for the CSR.
Generate the CSR with keytool
If you have already created your CSR and the Certificate Authority has issued the certificate, skip ahead to importing the CA reply, the step that fails silently when the alias does not match.
keytool comes with the JDK, so install a current JDK first if you do not have one. JDK 25 is the current long-term support release and JDK 26 is the current short-term release. The commands below run on JDK 17 and later, and the version differences that matter are noted where they occur. Confirm the tool is on your path:
java -version
keytool -help
jarsigner -version
A Java Runtime Environment on its own is not enough, and a working keytool is not proof that you have a JDK: the old Oracle JRE 8 ships keytool but not jarsigner. Run all three commands now. If the first two answer and the third does not, you are on a JRE, and installing a JDK at that point is easier than discovering it when you go to sign.
Step 1: Create the keystore and the key pair
Run this in a terminal, or in Command Prompt or PowerShell on Windows, from the directory where you want the keystore file to live:
keytool -genkeypair -alias codesign -keyalg RSA -keysize 3072 -storetype PKCS12 -keystore codesign.p12
Four details in that command differ from older instructions, and each one matters:
- -genkeypair, not -genkey. The old -genkey spelling still runs and keytool prints no warning about it, but it is only kept in the source as a legacy alias and it no longer appears anywhere in the JDK documentation. Write -genkeypair.
- -storetype PKCS12, not JKS. JKS is Oracle’s proprietary keystore format. PKCS12 is the industry standard one and has been the JDK default since Java 9. If you create a JKS keystore anyway, keytool warns you on every command that touches it: “The JKS keystore uses a proprietary format. It is recommended to migrate to PKCS12 which is an industry standard format.”
- The file name does not set the format. Naming a file keystore.jks does not make it a JKS keystore. keytool takes the type from -storetype, or from the keystore.type property in the JDK’s security file when you omit it. On JDK 9 and later that property is pkcs12, so a command that writes to keystore.jks without -storetype quietly produces a PKCS12 file with a misleading name.
- -keysize 3072, not 2048. The Baseline Requirements set RSA 3072 as the minimum for code signing, so a 2048-bit request is rejected. Current JDKs default to 3072 for RSA, but JDK 17 and earlier default to 2048, so pass the option explicitly and the command behaves the same everywhere.
The alias, codesign in the example, is the label for this entry inside the keystore. Choose something you will recognise, and write it down: every later command needs it, and a mismatch is what breaks the certificate import described further down.
An ECDSA key is also allowed. Substitute -keyalg EC -groupname secp256r1 for the RSA options if you prefer P-256, and confirm with your CA that the product you ordered supports ECDSA.
Step 2: Answer the prompts that build your distinguished name
keytool asks for a keystore password twice, then asks six questions in this exact order. The order matters: the second prompt asks for the organizational unit, not the organization, and older guides list it wrong, so a reader who types the company name there puts it in the wrong component of the name.
- What is your first and last name? This becomes the Common Name (CN), despite the wording. For a code signing certificate the CN is the publisher identity that users will see, so enter the exact legal name of your organization, or your own full legal name for an individual certificate. Do not enter a domain name here.
- What is the name of your organizational unit? The department, for example IT. Do not press Enter to skip it: keytool then writes the literal value Unknown into the name, and OU=Unknown ends up in your CSR. If you want no organizational unit at all, use the -dname form below and leave the OU component out of the string.
- What is the name of your organization? The registered legal name, spelled as it appears in official records. The CA verifies this against public registries.
- What is the name of your City or Locality? The city of registration, written in full.
- What is the name of your State or Province? The full name, not an abbreviation.
- What is the two-letter country code for this unit? The ISO code, for example US.
keytool then prints the assembled name back and asks you to confirm it:
Is CN=Example LLC, OU=IT, O=Example LLC, L=Miami, ST=Florida, C=US correct?
[no]:
The default answer is no, so pressing Enter sends you back through all six questions. Type yes to accept. Read the line carefully first: this is the whole distinguished name, not just the Common Name, and every component of it goes into the CSR.
There is no separate key password on a PKCS12 keystore. Older guides end this step with “enter a password for the key”, which is JKS behaviour. On a PKCS12 keystore the key password is the store password, and if you pass -keypass with a different value keytool tells you so: “Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified -keypass value.”
To skip the prompts entirely, supply the whole name with -dname. Keep the value in one pair of straight quotation marks:
keytool -genkeypair -alias codesign -keyalg RSA -keysize 3072 -storetype PKCS12 -keystore codesign.p12 -dname "CN=Example LLC, OU=IT, O=Example LLC, L=Miami, ST=Florida, C=US"
Leave -storepass off the command line and let keytool prompt for it. Passing a password as an argument writes it into your shell history and exposes it to anyone who can list running processes.
Step 3: Create the CSR
The keystore now holds a private key and a temporary self-signed certificate. Turn that entry into a certificate request:
keytool -certreq -alias codesign -keystore codesign.p12 -file codesign.csr
Enter the keystore password when prompted. You do not need -storetype here: keytool detects the format of a keystore file that already exists. The alias must be the one from step 1, because the CSR is signed by that entry’s private key.
This command does not create a private key. The key was created in step 1 and stays inside the keystore, which is why the keystore file and its password are now as sensitive as the key itself. Anyone who holds both can sign software in your name.
Step 4: Check the CSR before you send it
A rejected CSR costs a validation cycle, so decode it and read it back:
keytool -printcertreq -file codesign.csr
Confirm three things in the output. The Subject line should list your details in the right components, with the legal organization name in O and the publisher identity in CN. The public key line should read 3072-bit RSA key or larger. The signature algorithm should be a SHA-2 algorithm: current JDKs sign a 3072-bit RSA request with SHA384withRSA and older ones use SHA256withRSA, and either is fine. That algorithm only proves you hold the private key, and it is not the algorithm the CA will use to sign your certificate.
You can also paste the request into our CSR decoder to read the same fields in a browser.
When you submit the request, open the file in a plain-text editor and copy everything, including the first and last lines. keytool writes these exact markers, with five hyphens on each side:
-----BEGIN NEW CERTIFICATE REQUEST-----
MIID3TCCAkUCAQAwaDELMAkGA1UEBhMCVVMxEDAOBgNVBAgTB0Zsb3JpZGExDjAM
...base64 encoded request...
-----END NEW CERTIFICATE REQUEST-----
The wording NEW CERTIFICATE REQUEST is normal for keytool output and enrollment forms accept it. If your editor has replaced any run of hyphens with a long dash, the request will be refused: retype the markers as plain hyphens or copy the file with a code editor instead.
Generate the CSR on a token or HSM with keytool
This is the path that produces a CSR a public CA can act on. keytool talks to a hardware token through the SunPKCS11 provider, so the key pair is created inside the device and never exists as a file. Start by writing a small configuration file, for example token.cfg, that names your token and points at the PKCS#11 library your vendor installed:
name = token
library = /usr/local/lib/libeToken.so
Those two lines, name and library, are the only required ones. The library path is vendor-specific and differs by operating system, so take it from your token documentation rather than from this example. On Windows it is a DLL under the system directory. With no slot line, the provider attaches to the first slot the device reports, which is what you want when a single token is plugged in. If you have more than one reader or token, add either slotListIndex with the position in that list, counting from zero, or slot with the numeric slot ID your vendor utility prints. Only one of the two may appear in the file, and a slot ID is not the same number as a list position, so do not guess at slot = 0.
List what is on the device. The token supplies the alias, so you need this before anything else:
keytool -list -keystore NONE -storetype PKCS11 -providerClass sun.security.pkcs11.SunPKCS11 -providerArg token.cfg
-keystore NONE is required whenever the keystore is not a file, and the password prompt is asking for the token PIN. keytool also accepts -addprovider SunPKCS11 -providerarg token.cfg in place of the -providerClass and -providerArg pair; both forms work, and Certificate Authority documentation usually shows the older one.
With the alias in hand, generate the key on the device and then request the CSR against it:
keytool -genkeypair -alias codesign -keyalg RSA -keysize 3072 -keystore NONE -storetype PKCS11 -providerClass sun.security.pkcs11.SunPKCS11 -providerArg token.cfg -dname "CN=Example LLC, O=Example LLC, L=Miami, ST=Florida, C=US"
keytool -certreq -alias codesign -keystore NONE -storetype PKCS11 -providerClass sun.security.pkcs11.SunPKCS11 -providerArg token.cfg -file codesign.csr
Two caveats apply. Some tokens do not allow key generation over PKCS#11 and expect you to use the vendor’s own utility, which is fine: keytool can still create the CSR against a key the vendor tool generated. And keytool cannot produce the attestation file your CA will ask for, so generate that with the vendor tooling at the same time as the key, following the YubiKey or Luna HSM guide.
Import the CA reply into the same alias
When the certificate arrives, it has to go back into the entry that generated the CSR. Import it anywhere else and keytool still reports success while producing a keystore that cannot sign, so read this section before you run anything.
Import the CA’s root and any intermediate certificates first, each under its own alias:
keytool -importcert -trustcacerts -alias caroot -file root.crt -keystore codesign.p12
keytool prints the certificate it is about to store and asks Trust this certificate? with no as the default, so type yes. Check the fingerprint against the one your Certificate Authority publishes before you answer.
Skip the root import and the next command fails with a message that gives no hint about the cause:
keytool error: java.lang.Exception: Failed to establish chain from reply
Now import your issued certificate using the same alias you used in step 1:
keytool -importcert -alias codesign -file codesign.crt -keystore codesign.p12
The message you want is Certificate reply was installed in keystore. That means keytool recognised an existing private key under that alias and attached the issued certificate and its chain to it.
If you invent a new alias instead, keytool accepts the file and prints Certificate was added to keystore. That looks like success and is not. keytool has stored the certificate as a standalone trusted entry with no private key behind it, and that entry can never sign anything. The original alias, meanwhile, still holds the temporary self-signed certificate from step 1. Check which of the two you have:
keytool -list -keystore codesign.p12
Your signing alias must be listed as PrivateKeyEntry. An alias shown as trustedCertEntry is the mistake described above. Delete it with keytool -delete -alias wrongalias -keystore codesign.p12 and repeat the import against the correct alias. Add -v to the list command to confirm the entry now carries a full certificate chain rather than a single self-signed certificate.
On a hardware token there is nothing to import in most cases, because the CA loads the certificate onto the device before shipping it. If your CA sends you a certificate file for a key you generated on your own HSM, use the same -importcert command with the PKCS#11 options from the previous section.
Sign a JAR file with the certificate
The point of putting a code signing certificate in a Java keystore is signing JAR files with jarsigner, which also ships with the JDK. With the certificate installed under the correct alias:
jarsigner -keystore codesign.p12 -tsa https://your-ca-timestamp-url application.jar codesign
Always pass -tsa with the timestamp URL your Certificate Authority publishes. A timestamp records that the JAR was signed while the certificate was still valid, so the signature keeps working after the certificate expires. Without one, every copy of your software stops validating on the day the certificate lapses.
When the key lives on a token, point jarsigner at PKCS#11 exactly as keytool does:
jarsigner -keystore NONE -storetype PKCS11 -providerClass sun.security.pkcs11.SunPKCS11 -providerArg token.cfg -tsa https://your-ca-timestamp-url application.jar codesign
If the token has too little space for the full certificate chain, supply it separately with -certchain. Check the result afterwards:
jarsigner -verify -verbose -certs application.jar
A successful run prints jar verified along with the signer’s distinguished name and the timestamp details. Current JDKs use SHA-384 as the default digest algorithm, so you rarely need to set -digestalg or -sigalg by hand.
Other ways to create this request are covered in the OpenSSL, CertReq, Microsoft Management Console, and macOS Keychain Access guides, and the same hardware rule applies to all of them. See also our full set of code signing tutorials and the overview of CSR generation for code signing certificates. If you need a keytool CSR for a website certificate rather than a code signing one, follow the Tomcat or JBoss guide instead.
Frequently Asked Questions
Only if keytool generated the key inside a hardware token or HSM through PKCS#11, and you can supply the attestation the Certificate Authority asks for. A CSR created from an ordinary keystore file on your computer is a software key, and since June 1, 2023 public CAs do not issue code signing certificates against software keys. Software keystores remain fine for signing with an internal or enterprise CA.
Use -genkeypair. The -genkey spelling is a legacy alias that the JDK still accepts without any warning, but it has been absent from the documentation for many releases. Both do the same thing today; only one of them is documented.
Use PKCS12. It is an industry standard format and it has been the JDK default keystore type since Java 9, whereas JKS is Oracle-proprietary and makes keytool print a migration warning on every command. The file extension has no effect at all: keytool decides the format from -storetype, or from the keystore.type security property when you omit it, so a file named keystore.jks created on a modern JDK is usually a PKCS12 file. To convert an existing keystore, run keytool -importkeystore -srckeystore keystore.jks -destkeystore keystore.p12 -deststoretype pkcs12.
RSA 3072 bits or larger, which the Code Signing Baseline Requirements have required since June 1, 2021, or an equivalent ECDSA key such as P-256. Pass -keysize 3072 explicitly, because JDK 17 and earlier default to 2048 bits and that request is rejected.
You almost certainly imported the CA reply into a new alias rather than into the alias that generated the CSR. keytool then stores it as a standalone trusted certificate with no private key attached, and prints Certificate was added to keystore, which reads like success. Run keytool -list -keystore codesign.p12: the signing alias must appear as PrivateKeyEntry, not trustedCertEntry. Delete the wrong entry and import again with the original alias, and you should see Certificate reply was installed in keystore.
keytool cannot build a path from your issued certificate up to a certificate it already trusts. Import the CA’s root and intermediate certificates into the same keystore first, each under its own alias with -importcert -trustcacerts, then import your certificate again. Alternatively, import a single file that contains your certificate followed by the intermediates and the root.
No. A code signing certificate is identified by its code signing extended key usage, not by a toolchain, so the same certificate signs JAR files with jarsigner and Windows executables with signtool. What you do choose at order time is the delivery method, which decides whether the CA ships you a pre-configured token or you generate the key on hardware you already own.
With a token or HSM the key is inside the device and cannot be copied out, which is the entire point of the requirement. With a software keystore used for internal signing, the key sits in the keystore file, so the file and its password together are the secret: keep them in a restricted location, never commit either to source control, and let keytool prompt for the password instead of passing -storepass on the command line where it would land in your shell history.
Save 10% on SSL Certificates when ordering from SSL Dragon today!
Fast issuance, strong encryption, 99.99% browser trust, dedicated support, and 25-day money-back guarantee. Coupon code: SAVE10

