How to import an existing X.509 certificate and private key in Java keystore to use in SSL?
Asked Answered
M

16

291

I have a pair of X.509 cert and a key file.

How do I import those two in a single keystore? All examples I could Google always generate the key themselves, but I already have a key.

I have tried:

keytool -import  -keystore ./broker.ks -file mycert.crt

However, this only imports the certificate and not the key file. I have tried concatenating the cert and the key but got the same result.

How do I import the key?

Manual answered 25/5, 2009 at 11:34 Comment(2)
You actually have to write a bit of code to do this, and the details depend on the format of the private key you are trying to import. What format is your key? Can you explain what tools you used to generate the key and certificate that you have?Dikmen
For two-way SSL (client and server certificate) with Spring Boot see https://mcmap.net/q/102177/-java-https-client-certificate-authenticationCocktail
Y
86

Believe or not, keytool does not provide such basic functionality like importing private key to keystore. You can try this workaround with merging PKSC12 file with private key to a keystore:

keytool -importkeystore \
  -deststorepass storepassword \
  -destkeypass keypassword \
  -destkeystore my-keystore.jks \
  -srckeystore cert-and-key.p12 \
  -srcstoretype PKCS12 \
  -srcstorepass p12password \
  -alias 1

Or just use more user-friendly KeyMan from IBM for keystore handling instead of keytool.

Yokoyama answered 25/5, 2009 at 17:42 Comment(4)
According to CoverosGene's answer keytool supports it since Java 6. This is the link he providedAlurd
For what it's worth, for all the noise on this subject, the best link is @Matej's 'workaround' link to this 2008 post: cunning.sharp.fm/2008/06/importing_private_keys_into_a.htmlSurcease
KeyMan doesn't seem all that user-friendly to me.Limestone
Broken link. Please include the details of the solution directly into the answer :-(Espinosa
E
622

I used the following two steps which I found in the comments/posts linked in the other answers:

Step one: Convert the x.509 cert and key to a pkcs12 file

openssl pkcs12 -export -in server.crt -inkey server.key \
               -out server.p12 -name [some-alias] \
               -CAfile ca.crt -caname root

Note: Make sure you put a password on the pkcs12 file - otherwise you'll get a null pointer exception when you try to import it. (In case anyone else had this headache). (Thanks jocull!)

Note 2: You might want to add the -chain option to preserve the full certificate chain. (Thanks Mafuba)

Step two: Convert the pkcs12 file to a Java keystore

keytool -importkeystore \
        -deststorepass [changeit] -destkeypass [changeit] -destkeystore server.keystore \
        -srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass some-password \
        -alias [some-alias]

Finished

OPTIONAL Step zero: Create self-signed certificate

openssl genrsa -out server.key 2048
openssl req -new -out server.csr -key server.key
openssl x509 -req -days 365 -in server.csr -signkey server.key -out server.crt

FAQ: I get error IOException: keystore password was incorrect

If you are using OpenSSL 3.0 and a JDK newer than Java8u302 and get the following error:

keytool error: java.io.IOException: keystore password was incorrect

You might caught in a change pf default cypher within openssl. This Stack Overflow Answer provides an answer. Maybe thank Thomas with an upvote.

Enchantress answered 22/11, 2011 at 9:52 Comment(22)
Make sure you put a password on the p12 file - otherwise you'll get a null reference exception when you try to import it. (In case anyone else had this headache)Centering
After creating my key and CSR with openssl, and then trying to make it work with Jetty, this did the trick. Many thinks!Tailrace
In my case at step one the option -CAfile ca.crt -caname root didn't correctly output the CA certificates. Instead I used -certfile concatenedCAFiles.pemLarghetto
Don't forget to use the -chain argument with openssl to include the full certificate chain in your pfx/p12 file if you want that in your key store.Bittersweet
In a Windows environment, pvk2pfx (a standard VS tool available in the VS cmd prompt) will spit out a .pfx--equivalent to a .p12. @jocull's advice is still relevant; put a password on it. No openssl needed.Kimberly
Adding to openssl pkcs12 -chain comment by @Mufaba. Trust-chain certificates are missing from "keytool -list" unless you use the verbose option like "keytool -list -v ..." This was confusing me because keytool said only one certificate imported and -list was not showing my chain until I added -v to it. With -v you will see "Certificate chain length: #" AND "Certificate[#]". Note that -caname is unnecessary because JKS chain ignores alias for trust-chain.Ellmyer
I get the following error: keytool error: java.lang.Exception: Alias <...> does not existSidesman
@JonTirsen: did you use the same alias in both calls (I used some-alias in the example)? If you did: could you please create a pastebin/gist listing of all steps and their full output.Enchantress
For Tomcat in particular it's imperative that the keystore and the key passwords are same. When you import a .p12 the key will have the password of the original .p12. Tomcat will fail with java.security.UnrecoverableKeyException: Cannot recover key. In other words: if you need to execute -deststorepass changeit -srcstorepass some-password with different passwords, then you must include -destkeypass changeit (with same password as -deststorepass)Bucharest
Lifesaver about the REQUIREMENT to use deststorepass and destkeypass parameters. For those of us that hate passing passwords into the command string for all to see/archive, not a way around it this time I guess.Mernamero
If you end up with the error message "Error unable to get local issuer certificate getting chain." while using the -chain option, you need to import the CA Root and maybe also the CA Intermediate Certficates like described here: gagravarr.org/writing/openssl-certs/others.shtml#ca-openssl into the openssl Certficate folderSchexnayder
@Mernamero for all -*pass you can add ":file [file]" and not put password on command line, i.e. -deststorepass:file .kpNeutral
Great answer! In my case there were 2 CA's in the chain so I needed to merge the CA's pem files in one and that to the -CAfile parameter (toghether with -chain)Multicolor
The p12 file produced by openssl is already a Java keystore. Step 2 simply merges this new keystore into an existing one, which is only necessary if you have an existing (old) keystore. Am I missing something here?Prestige
@reto, Do you know why i running the one step and did not happen anythings, this is a long execution?Wend
@GavrielCohen the command should complete immediately. You probably forgot -in or -inkey and the system is assuming you want to paste that part via stdin. Check your command carefully. Maybe you are also forgetting an '\' at the end of a line.Enchantress
Here is the pkcs12 creation with passwords: openssl pkcs12 -export -in server.crt -inkey server.key -out server.p12 -name [some-alias] -passin pass:some-password -passout pass:some-password -CAfile ca.crt -caname rootMistrial
Suggesting it is important to add a password on the keystore while not adding it in the command makes things rather confusing.Coronet
For me it was important to use the full chain in PEM format as input file for the openssl command (-in server.crt). This means to concatenate CA certificate, personal certificate, private key in a single file (the format with `-----BEGIN CERTIFICATE-----'...) and use it in place of "server.crt". This allowed me to obtain a jks file with the complete certificate chain (i.e. "Certificate chain length: 2")Decal
Thanks! I've get valid keystore at step 1, so step 2 was redudant for me. Here is full description https://mcmap.net/q/102177/-java-https-client-certificate-authenticationCocktail
You do not need password on source p12 file. You can pass empty password to keytool program just add parameter -srcstorepass "".Silurid
If you get: Error unable to get issuer certificate getting chain. make sure you have the full chain: root + intermediate + your-cert. You can download the root and intermediate certificates from the Certificate Authority web site.Pinery
E
144

Keytool in Java 6 does have this capability: Importing private keys into a Java keystore using keytool

Here are the basic details from that post.

  1. Convert the existing cert to a PKCS12 using OpenSSL. A password is required when asked or the 2nd step will complain.

    openssl pkcs12 -export -in [my_certificate.crt] -inkey [my_key.key] \
      -out [keystore.p12] -name [new_alias] -CAfile [my_ca_bundle.crt] \
      -caname root
    
  2. Convert the PKCS12 to a Java Keystore File.

    keytool -importkeystore -deststorepass [new_keystore_pass] \
      -destkeypass [new_key_pass] -destkeystore [keystore.jks] \
      -srckeystore [keystore.p12] -srcstoretype PKCS12 \
      -srcstorepass [pass_used_in_p12_keystore] \
      -alias [alias_used_in_p12_keystore]
    
Enthetic answered 26/1, 2010 at 17:26 Comment(5)
The answer by @Enchantress contains the contents of this link.Bittersweet
As stated by @Mafuba, you must still create a separate pkcs12 keystore with non-java tool like openssl - then this can be imported into a jks store by keytool as stated in the answer by reto.Ellmyer
One thing that makes this a good answer is the fact that the input certs are clearly specified in the brackets.Barbbarba
FWIW, the output of step 1 should already be usable as a Java keystore (so step 2 may not be required - unless you do need to import the cert+key into an existing keystore) - as already mentioned in a previous answer by @PrestigeVocative
You may skip password in first step and set password in second step as "" i.e. -srcstorepass ""Silurid
Y
86

Believe or not, keytool does not provide such basic functionality like importing private key to keystore. You can try this workaround with merging PKSC12 file with private key to a keystore:

keytool -importkeystore \
  -deststorepass storepassword \
  -destkeypass keypassword \
  -destkeystore my-keystore.jks \
  -srckeystore cert-and-key.p12 \
  -srcstoretype PKCS12 \
  -srcstorepass p12password \
  -alias 1

Or just use more user-friendly KeyMan from IBM for keystore handling instead of keytool.

Yokoyama answered 25/5, 2009 at 17:42 Comment(4)
According to CoverosGene's answer keytool supports it since Java 6. This is the link he providedAlurd
For what it's worth, for all the noise on this subject, the best link is @Matej's 'workaround' link to this 2008 post: cunning.sharp.fm/2008/06/importing_private_keys_into_a.htmlSurcease
KeyMan doesn't seem all that user-friendly to me.Limestone
Broken link. Please include the details of the solution directly into the answer :-(Espinosa
C
23

Using Let's Encrypt certificates

Assuming you've created your certificates and private keys with Let's Encrypt in /etc/letsencrypt/live/you.com:

1. Create a PKCS #12 file

openssl pkcs12 -export -in fullchain.pem -inkey privkey.pem -out pkcs.p12 \
        -name letsencrypt

This combines your SSL certificate fullchain.pem and your private key privkey.pem into a single file, pkcs.p12.

You'll be prompted for a password for pkcs.p12.

The export option specifies that a PKCS #12 file will be created rather than parsed (according to the manual).

2. Create the Java keystore

keytool -importkeystore -destkeystore keystore.jks -srckeystore pkcs.p12 \
        -srcstoretype PKCS12 -alias letsencrypt

If keystore.jks doesn't exist, it will be created containing the pkcs.12 from the previous step. Otherwise, you'll import pkcs.12 into the existing keystore.


These instructions are derived from the blog post "Create a Java Keystore (.JKS) from Let's Encrypt Certificates" by Maximilian Böhm.

Here's more on the different kind of files in /etc/letsencrypt/live/you.com/.

Corkscrew answered 19/6, 2019 at 11:29 Comment(1)
I created and installed a LetsEncrypt SSL onto Tomcat, thanks to this.Costume
L
12

First convert to p12:

openssl pkcs12 -export -in [filename-certificate] -inkey [filename-key] -name [host] -out [filename-new-PKCS-12.p12]

Create new JKS from p12:

keytool -importkeystore -deststorepass [password] -destkeystore [filename-new-keystore.jks] -srckeystore [filename-new-PKCS-12.p12] -srcstoretype PKCS12
Lustral answered 1/6, 2017 at 8:49 Comment(0)
N
11

And one more:

#!/bin/bash

# We have:
#
# 1) $KEY : Secret key in PEM format ("-----BEGIN RSA PRIVATE KEY-----") 
# 2) $LEAFCERT : Certificate for secret key obtained from some
#    certification outfit, also in PEM format ("-----BEGIN CERTIFICATE-----")   
# 3) $CHAINCERT : Intermediate certificate linking $LEAFCERT to a trusted
#    Self-Signed Root CA Certificate 
#
# We want to create a fresh Java "keystore" $TARGET_KEYSTORE with the
# password $TARGET_STOREPW, to be used by Tomcat for HTTPS Connector.
#
# The keystore must contain: $KEY, $LEAFCERT, $CHAINCERT
# The Self-Signed Root CA Certificate is obtained by Tomcat from the
# JDK's truststore in /etc/pki/java/cacerts

# The non-APR HTTPS connector (APR uses OpenSSL-like configuration, much
# easier than this) in server.xml looks like this 
# (See: https://tomcat.apache.org/tomcat-6.0-doc/ssl-howto.html):
#
#  <Connector port="8443" protocol="org.apache.coyote.http11.Http11Protocol"
#                SSLEnabled="true"
#                maxThreads="150" scheme="https" secure="true"
#                clientAuth="false" sslProtocol="TLS"
#                keystoreFile="/etc/tomcat6/etl-web.keystore.jks"
#                keystorePass="changeit" />
#

# Let's roll:    

TARGET_KEYSTORE=/etc/tomcat6/foo-server.keystore.jks
TARGET_STOREPW=changeit

TLS=/etc/pki/tls

KEY=$TLS/private/httpd/foo-server.example.com.key
LEAFCERT=$TLS/certs/httpd/foo-server.example.com.pem
CHAINCERT=$TLS/certs/httpd/chain.cert.pem

# ----
# Create PKCS#12 file to import using keytool later
# ----

# From https://www.sslshopper.com/ssl-converter.html:
# The PKCS#12 or PFX format is a binary format for storing the server certificate,
# any intermediate certificates, and the private key in one encryptable file. PFX
# files usually have extensions such as .pfx and .p12. PFX files are typically used 
# on Windows machines to import and export certificates and private keys.

TMPPW=$$ # Some random password

PKCS12FILE=`mktemp`

if [[ $? != 0 ]]; then
  echo "Creation of temporary PKCS12 file failed -- exiting" >&2; exit 1
fi

TRANSITFILE=`mktemp`

if [[ $? != 0 ]]; then
  echo "Creation of temporary transit file failed -- exiting" >&2; exit 1
fi

cat "$KEY" "$LEAFCERT" > "$TRANSITFILE"

openssl pkcs12 -export -passout "pass:$TMPPW" -in "$TRANSITFILE" -name etl-web > "$PKCS12FILE"

/bin/rm "$TRANSITFILE"

# Print out result for fun! Bug in doc (I think): "-pass " arg does not work, need "-passin"

openssl pkcs12 -passin "pass:$TMPPW" -passout "pass:$TMPPW" -in "$PKCS12FILE" -info

# ----
# Import contents of PKCS12FILE into a Java keystore. WTF, Sun, what were you thinking?
# ----

if [[ -f "$TARGET_KEYSTORE" ]]; then
  /bin/rm "$TARGET_KEYSTORE"
fi

keytool -importkeystore \
   -deststorepass  "$TARGET_STOREPW" \
   -destkeypass    "$TARGET_STOREPW" \
   -destkeystore   "$TARGET_KEYSTORE" \
   -srckeystore    "$PKCS12FILE" \
   -srcstoretype  PKCS12 \
   -srcstorepass  "$TMPPW" \
   -alias foo-the-server

/bin/rm "$PKCS12FILE"

# ----
# Import the chain certificate. This works empirically, it is not at all clear from the doc whether this is correct
# ----

echo "Importing chain"

TT=-trustcacerts

keytool -import $TT -storepass "$TARGET_STOREPW" -file "$CHAINCERT" -keystore "$TARGET_KEYSTORE" -alias chain

# ----
# Print contents
# ----

echo "Listing result"

keytool -list -storepass "$TARGET_STOREPW" -keystore "$TARGET_KEYSTORE"
Neibart answered 27/7, 2015 at 23:0 Comment(1)
I like this script because it takes care of the complete ecosystem, especially how to handle the intermediate CA cert. Other answers, while very helpful in handling the leaf cert and the corresponding private key, doesn't spell out how to handle the intermediate CA cert.Banal
C
8

In my case I had a pem file which contained two certificates and an encrypted private key to be used in mutual SSL authentication. So my pem file looked like this:

-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
Proc-Type: 4,ENCRYPTED
DEK-Info: DES-EDE3-CBC,C8BF220FC76AA5F9
...
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----

Here is what I did:

Split the file into three separate files, so that each one contains just one entry, starting with "---BEGIN.." and ending with "---END.." lines. Lets assume we now have three files: cert1.pem cert2.pem and pkey.pem

Convert pkey.pem into DER format using openssl and the following syntax:

openssl pkcs8 -topk8 -nocrypt -in pkey.pem -inform PEM -out pkey.der -outform DER

Note, that if the private key is encrypted you need to supply a password( obtain it from the supplier of the original pem file ) to convert to DER format, openssl will ask you for the password like this: "enter a pass phraze for pkey.pem: " If conversion is successful, you will get a new file called "pkey.der"

Create a new java key store and import the private key and the certificates:

String keypass = "password";  // this is a new password, you need to come up with to protect your java key store file
String defaultalias = "importkey";
KeyStore ks = KeyStore.getInstance("JKS", "SUN");

// this section does not make much sense to me, 
// but I will leave it intact as this is how it was in the original example I found on internet:   
ks.load( null, keypass.toCharArray());
ks.store( new FileOutputStream ( "mykeystore"  ), keypass.toCharArray());
ks.load( new FileInputStream ( "mykeystore" ),    keypass.toCharArray());
// end of section..


// read the key file from disk and create a PrivateKey

FileInputStream fis = new FileInputStream("pkey.der");
DataInputStream dis = new DataInputStream(fis);
byte[] bytes = new byte[dis.available()];
dis.readFully(bytes);
ByteArrayInputStream bais = new ByteArrayInputStream(bytes);

byte[] key = new byte[bais.available()];
KeyFactory kf = KeyFactory.getInstance("RSA");
bais.read(key, 0, bais.available());
bais.close();

PKCS8EncodedKeySpec keysp = new PKCS8EncodedKeySpec ( key );
PrivateKey ff = kf.generatePrivate (keysp);


// read the certificates from the files and load them into the key store:

Collection  col_crt1 = CertificateFactory.getInstance("X509").generateCertificates(new FileInputStream("cert1.pem"));
Collection  col_crt2 = CertificateFactory.getInstance("X509").generateCertificates(new FileInputStream("cert2.pem"));

Certificate crt1 = (Certificate) col_crt1.iterator().next();
Certificate crt2 = (Certificate) col_crt2.iterator().next();
Certificate[] chain = new Certificate[] { crt1, crt2 };

String alias1 = ((X509Certificate) crt1).getSubjectX500Principal().getName();
String alias2 = ((X509Certificate) crt2).getSubjectX500Principal().getName();

ks.setCertificateEntry(alias1, crt1);
ks.setCertificateEntry(alias2, crt2);

// store the private key
ks.setKeyEntry(defaultalias, ff, keypass.toCharArray(), chain );

// save the key store to a file         
ks.store(new FileOutputStream ( "mykeystore" ),keypass.toCharArray());

(optional) Verify the content of your new key store:

keytool -list -keystore mykeystore -storepass password

Keystore type: JKS Keystore provider: SUN

Your keystore contains 3 entries

cn=...,ou=...,o=.., Sep 2, 2014, trustedCertEntry, Certificate fingerprint (SHA1): 2C:B8: ...

importkey, Sep 2, 2014, PrivateKeyEntry, Certificate fingerprint (SHA1): 9C:B0: ...

cn=...,o=...., Sep 2, 2014, trustedCertEntry, Certificate fingerprint (SHA1): 83:63: ...

(optional) Test your certificates and private key from your new key store against your SSL server: ( You may want to enable debugging as an VM option: -Djavax.net.debug=all )

        char[] passw = "password".toCharArray();
        KeyStore ks = KeyStore.getInstance("JKS", "SUN");
        ks.load(new FileInputStream ( "mykeystore" ), passw );

        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(ks, passw);

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ks);
        TrustManager[] tm = tmf.getTrustManagers();

        SSLContext sclx = SSLContext.getInstance("TLS");
        sclx.init( kmf.getKeyManagers(), tm, null);

        SSLSocketFactory factory = sclx.getSocketFactory();
        SSLSocket socket = (SSLSocket) factory.createSocket( "192.168.1.111", 443 );
        socket.startHandshake();

        //if no exceptions are thrown in the startHandshake method, then everything is fine..

Finally register your certificates with HttpsURLConnection if plan to use it:

        char[] passw = "password".toCharArray();
        KeyStore ks = KeyStore.getInstance("JKS", "SUN");
        ks.load(new FileInputStream ( "mykeystore" ), passw );

        KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        kmf.init(ks, passw);

        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(ks);
        TrustManager[] tm = tmf.getTrustManagers();

        SSLContext sclx = SSLContext.getInstance("TLS");
        sclx.init( kmf.getKeyManagers(), tm, null);

        HostnameVerifier hv = new HostnameVerifier()
        {
            public boolean verify(String urlHostName, SSLSession session)
            {
                if (!urlHostName.equalsIgnoreCase(session.getPeerHost()))
                {
                    System.out.println("Warning: URL host '" + urlHostName + "' is different to SSLSession host '" + session.getPeerHost() + "'.");
                }
                return true;
            }
        };

        HttpsURLConnection.setDefaultSSLSocketFactory( sclx.getSocketFactory() );
        HttpsURLConnection.setDefaultHostnameVerifier(hv);
Calculus answered 4/9, 2014 at 16:18 Comment(2)
However, Bruno mentioned that this hostname verifier is wrong: "Your hostname verifier is wrong, session.getPeerHost() doesn't return the name in the certificate, but the name you connected with (i.e. the urlHostName here), so that's always going to be true. You're always returning true anyway. – Bruno". It worked for me though, but I would appreciate if somebody shows me how to write a good host name verifier.Calculus
Of course it will "work" for you, since it will never produce an error, even when it should. Leave the default hostname verifier used by HttpsURLConnection instead of trying to writing your own. (Another problem with your example is that you're using the same keystore as a keystore and a truststore, which isn't always a good idea...)Sealskin
M
6

Yes, it's indeed a sad fact that keytool has no functionality to import a private key.

For the record, at the end I went with the solution described here

Manual answered 26/5, 2009 at 7:19 Comment(0)
C
6

What I was trying to achieve was using already provided private key and certificate to sign message that was going someplace that needed to make sure that the message was coming from me (private keys sign while public keys encrypt).

So if you already have a .key file and a .crt file?

Try this:

Step1: Convert the key and cert to .p12 file

openssl pkcs12 -export -in certificate.crt -inkey privateKey.key -name alias -out yourconvertedfile.p12

Step 2: Import the key and create a .jsk file with a single command

keytool -importkeystore -deststorepass changeit -destkeystore keystore.jks -srckeystore umeme.p12 -srcstoretype PKCS12

Step 3: In your java:

char[] keyPassword = "changeit".toCharArray();

KeyStore keyStore = KeyStore.getInstance("JKS");
InputStream keyStoreData = new FileInputStream("keystore.jks");

keyStore.load(keyStoreData, keyPassword);
KeyStore.ProtectionParameter entryPassword = new KeyStore.PasswordProtection(keyPassword);
KeyStore.PrivateKeyEntry privateKeyEntry = (KeyStore.PrivateKeyEntry)keyStore.getEntry("alias", entryPassword);

System.out.println(privateKeyEntry.toString());

If you need to sign some string using this key do the following:

Step 1: Convert the text you want to encrypt

byte[] data = "test".getBytes("UTF8");

Step 2: Get base64 encoded private key

keyStore.load(keyStoreData, keyPassword);

//get cert, pubkey and private key from the store by alias
Certificate cert = keyStore.getCertificate("localhost");
PublicKey publicKey = cert.getPublicKey();
KeyPair keyPair = new KeyPair(publicKey, (PrivateKey) key);

//sign with this alg
Signature sig = Signature.getInstance("SHA1WithRSA");
sig.initSign(keyPair.getPrivate());
sig.update(data);
byte[] signatureBytes = sig.sign();
System.out.println("Signature:" + Base64.getEncoder().encodeToString(signatureBytes));

sig.initVerify(keyPair.getPublic());
sig.update(data);

System.out.println(sig.verify(signatureBytes));

References:

  1. How to import an existing x509 certificate and private key in Java keystore to use in SSL?
  2. http://tutorials.jenkov.com/java-cryptography/keystore.html
  3. http://www.java2s.com/Code/Java/Security/RetrievingaKeyPairfromaKeyStore.htm
  4. How to sign string with private key

Final program

public static void main(String[] args) throws Exception {

    byte[] data = "test".getBytes("UTF8");

    // load keystore
    char[] keyPassword = "changeit".toCharArray();

    KeyStore keyStore = KeyStore.getInstance("JKS");
    //System.getProperty("user.dir") + "" < for a file in particular path 
    InputStream keyStoreData = new FileInputStream("keystore.jks");
    keyStore.load(keyStoreData, keyPassword);

    Key key = keyStore.getKey("localhost", keyPassword);

    Certificate cert = keyStore.getCertificate("localhost");

    PublicKey publicKey = cert.getPublicKey();

    KeyPair keyPair = new KeyPair(publicKey, (PrivateKey) key);

    Signature sig = Signature.getInstance("SHA1WithRSA");

    sig.initSign(keyPair.getPrivate());
    sig.update(data);
    byte[] signatureBytes = sig.sign();
    System.out.println("Signature:" + Base64.getEncoder().encodeToString(signatureBytes));

    sig.initVerify(keyPair.getPublic());
    sig.update(data);

    System.out.println(sig.verify(signatureBytes));
}
Commercial answered 18/3, 2019 at 11:30 Comment(1)
Step 1 was all I needed for a 1and1.com / ionos.com cert which provided a private key along with both root and intermediate certs.Oread
D
5

You can use these steps to import the key to an existing keystore. The instructions are combined from answers in this thread and other sites. These instructions worked for me (the java keystore):

  1. Run

openssl pkcs12 -export -in yourserver.crt -inkey yourkey.key -out server.p12 -name somename -certfile yourca.crt -caname root

(If required put the -chain option. Putting that failed for me). This will ask for the password - you must give the correct password else you will get an error (heading error or padding error etc).

  1. It will ask you to enter a new password - you must enter a password here - enter anything but remember it. (Let us assume you enter Aragorn).
  2. This will create the server.p12 file in the pkcs format.
  3. Now to import it into the *.jks file run:
    keytool -importkeystore -srckeystore server.p12 -srcstoretype PKCS12 -destkeystore yourexistingjavakeystore.jks -deststoretype JKS -deststorepass existingjavastorepassword -destkeypass existingjavastorepassword
    (Very important - do not leave out the deststorepass and the destkeypass parameters.)
  4. It will ask you for the src key store password. Enter Aragorn and hit enter. The certificate and key is now imported into your existing java keystore.
Depopulate answered 14/7, 2016 at 13:47 Comment(0)
D
5

Based on the answers above, here is how to create a brand new keystore for your java based web server, out of an independently created Comodo cert and private key using keytool (requires JDK 1.6+)

  1. Issue this command and at the password prompt enter somepass - 'server.crt' is your server's cert and 'server.key' is the private key you used for issuing the CSR: openssl pkcs12 -export -in server.crt -inkey server.key -out server.p12 -name www.yourdomain.com -CAfile AddTrustExternalCARoot.crt -caname "AddTrust External CA Root"

  2. Then use keytool to convert the p12 keystore into a jks keystore: keytool -importkeystore -deststorepass somepass -destkeypass somepass -destkeystore keystore.jks -srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass somepass

Then import the other two root/intermediate certs you received from Comodo:

  1. Import COMODORSAAddTrustCA.crt: keytool -import -trustcacerts -alias cert1 -file COMODORSAAddTrustCA.crt -keystore keystore.jks

  2. Import COMODORSADomainValidationSecureServerCA.crt: keytool -import -trustcacerts -alias cert2 -file COMODORSADomainValidationSecureServerCA.crt -keystore keystore.jks

Delaney answered 13/12, 2016 at 23:48 Comment(0)
A
3

Previous answers point out correctly that you can only do this with the standard JDK tools by converting the JKS file into PKCS #12 format first. If you're interested, I put together a compact utility to import OpenSSL-derived keys into a JKS-formatted keystore without having to convert the keystore to PKCS #12 first: http://commandlinefanatic.com/cgi-bin/showarticle.cgi?article=art049

You would use the linked utility like this:

$ openssl req -x509 -newkey rsa:2048 -keyout localhost.key -out localhost.csr -subj "/CN=localhost"

(sign the CSR, get back localhost.cer)

$ openssl rsa -in localhost.key -out localhost.rsa
Enter pass phrase for localhost.key:
writing RSA key
$ java -classpath . KeyImport -keyFile localhost.rsa -alias localhost -certificateFile localhost.cer -keystore localhost.jks -keystorePassword changeit -keystoreType JKS -keyPassword changeit
Aviva answered 2/3, 2016 at 19:23 Comment(3)
Just linking to your own library (or utility) is not a good answer. Linking to it, explaining why it solves the problem, providing code using it to do so and disclaiming makes for a better answer. See: How can I link to an external resource in a community-friendly way?Cordillera
Not sure what you mean by "disclaim", but I added an example.Aviva
Great! That's a canned comment, so part didn't apply - disclaim means to report your affiliation with the linked product or service, which you did with "I put together..."Cordillera
W
3

If you have a PEM file (e.g. server.pem) containing:

  • the trusted certificate
  • the private key

then you can import the certificate and key into a JKS keystore like this:

1) Copy the private key from the PEM file into an ascii file (e.g. server.key)

2) Copy the cert from the PEM file into an ascii file (e.g. server.crt)

3) Export the cert and key into a PKCS12 file:

$ openssl pkcs12 -export -in server.crt -inkey server.key \
                 -out server.p12 -name [some-alias] -CAfile server.pem -caname root
  • the PEM file can be used as the argument to the -CAfile option.
  • you are prompted for an 'export' password.
  • if doing this in git bash then add winpty to the start of the command so the export password can be entered.

4) Convert the PKCS12 file to a JKS keystore:

$ keytool -importkeystore -deststorepass changeit -destkeypass changeit \
          -destkeystore keystore.jks  -srckeystore server.p12 -srcstoretype PKCS12 \
          -srcstorepass changeit
  • the srcstorepass password should match the export password from step 3)
Wolfram answered 16/1, 2019 at 0:0 Comment(0)
T
1

Just make a PKCS12 keystore, Java can use it directly now. In fact, if you list a Java-style keystore, keytool itself alerts you to the fact that PKCS12 is now the preferred format.

openssl pkcs12 -export -in server.crt -inkey server.key \
               -out server.p12 -name [some-alias] \
               -CAfile ca.crt -caname root -chain

You should have received all three files (server.crt, server.key, ca.crt) from your certificate provider. I am not sure what "-caname root" actually means, but it seems to have to be specified that way.

In the Java code, make sure to specify the right keystore type.

KeyStore.getInstance("PKCS12")

I got my comodo.com-issued SSL certificate working fine in NanoHTTPD this way.

Trochal answered 31/12, 2018 at 16:45 Comment(0)
V
0

in a case of Elliptic Curve and answer the question import an existing x509 certificate and private key in Java keystore, you may want to have a look also to this thread How to read EC Private key in java which is in .pem file format

Vaginismus answered 20/3, 2019 at 21:49 Comment(0)
A
0

If you have received a combined cert and key in a single .pem file, like the MongoDB Atlas' authentication, then,

Open the pem file with a text editor and split them into two files, for example cert.pem and key.pem (where you can make a split is very clear in the file) and then use the openssl command to create a single p12 format file like this:

 openssl pkcs12 -export -out server.p12 -name test\
 -in cert.pem -inkey key.pem

I am using Java 8 and as it turns out at least in Java 8 or later the resulting p12 (server.p12) is now the keystore file so you can use it directly without a need to use the keytool if you do not need to add any more certs to it.

Aerospace answered 24/6, 2021 at 21:47 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.