How to properly import a selfsigned certificate into Java keystore that is available to all Java applications by default?

442,685

Solution 1

On Windows the easiest way is to use the program portecle.

  1. Download and install portecle.
  2. First make 100% sure you know which JRE or JDK is being used to run your program. On a 64 bit Windows 7 there could be quite a few JREs. Process Explorer can help you with this or you can use: System.out.println(System.getProperty("java.home"));
  3. Copy the file JAVA_HOME\lib\security\cacerts to another folder.
  4. In Portecle click File > Open Keystore File
  5. Select the cacerts file
  6. Enter this password: changeit
  7. Click Tools > Import Trusted Certificate
  8. Browse for the file mycertificate.pem
  9. Click Import
  10. Click OK for the warning about the trust path.
  11. Click OK when it displays the details about the certificate.
  12. Click Yes to accept the certificate as trusted.
  13. When it asks for an alias click OK and click OK again when it says it has imported the certificate.
  14. Click save. Don’t forget this or the change is discarded.
  15. Copy the file cacerts back where you found it.

On Linux:

You can download the SSL certificate from a web server that is already using it like this:

$ echo -n | openssl s_client -connect www.example.com:443 | \
   sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /tmp/examplecert.crt

Optionally verify the certificate information:

$ openssl x509 -in /tmp/examplecert.crt -text

Import the certificate into the Java cacerts keystore:

$ keytool -import -trustcacerts -keystore /opt/java/jre/lib/security/cacerts \
   -storepass changeit -noprompt -alias mycert -file /tmp/examplecert.crt

Solution 2

    D:\Java\jdk1.5.0_10\bin\keytool -import -file "D:\Certificates\SDS services\Dev\dev-sdsservices-was8.infavig.com.cer" -keystore "D:\Java\jdk1.5.0_10\jre\lib\security\cacerts" -alias "sds certificate"

Solution 3

I ended up writing a small script that adds the certificates to the keystores, so it is much easier to use.

You can get the latest version from https://github.com/ssbarnea/keytool-trust

#!/bin/bash
# version 1.0
# https://github.com/ssbarnea/keytool-trust
REMHOST=$1
REMPORT=${2:-443}

KEYSTORE_PASS=changeit
KEYTOOL="sudo keytool"

# /etc/java-6-sun/security/cacerts

for CACERTS in  /usr/lib/jvm/java-8-oracle/jre/lib/security/cacerts \
    /usr/lib/jvm/java-7-oracle/jre/lib/security/cacerts \
    "/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home/lib/security/cacerts" \
    "/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/MacOS/itms/java/lib/security/cacerts"
do

if [ -e "$CACERTS" ]
then
    echo --- Adding certs to $CACERTS

# FYI: the default keystore is located in ~/.keystore

if [ -z "$REMHOST" ]
    then
    echo "ERROR: Please specify the server name to import the certificatin from, eventually followed by the port number, if other than 443."
    exit 1
    fi

set -e

rm -f $REMHOST:$REMPORT.pem

if openssl s_client -connect $REMHOST:$REMPORT 1>/tmp/keytool_stdout 2>/tmp/output </dev/null
        then
        :
        else
        cat /tmp/keytool_stdout
        cat /tmp/output
        exit 1
        fi

if sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' </tmp/keytool_stdout > /tmp/$REMHOST:$REMPORT.pem
        then
        :
        else
        echo "ERROR: Unable to extract the certificate from $REMHOST:$REMPORT ($?)"
        cat /tmp/output
        fi

if $KEYTOOL -list -storepass ${KEYSTORE_PASS} -alias $REMHOST:$REMPORT >/dev/null
    then
    echo "Key of $REMHOST already found, skipping it."
    else
    $KEYTOOL -import -trustcacerts -noprompt -storepass ${KEYSTORE_PASS} -alias $REMHOST:$REMPORT -file /tmp/$REMHOST:$REMPORT.pem
    fi

if $KEYTOOL -list -storepass ${KEYSTORE_PASS} -alias $REMHOST:$REMPORT -keystore "$CACERTS" >/dev/null
    then
    echo "Key of $REMHOST already found in cacerts, skipping it."
    else
    $KEYTOOL -import -trustcacerts -noprompt -keystore "$CACERTS" -storepass ${KEYSTORE_PASS} -alias $REMHOST:$REMPORT -file /tmp/$REMHOST:$REMPORT.pem
    fi

fi

done

```

Solution 4

This worked for me. :)

sudo keytool -importcert -file filename.cer -alias randomaliasname -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit 

Solution 5

You can use keytool with your Java installation which should be in $JAVA_HOME/bin. The Java keystore is located in $JAVA_HOME/lib/security/cacerts or $JAVA_HOME/jre/lib/security/cacerts which depends on if you have the JDK or JRE installed.

If using Java 9 or later, you don't need to know the exact location. You can use the -cacerts option as a shortcut.

Java 9+

So with Java 9 (aka Java 1.9) or later, simply use

keytool -importcert -trustcacerts -cacerts -file myCert.pem -alias myCert

Earlier Java versions

With Java 8 (aka 1.8) or older, you must specify the keystore location like so

keytool -importcert -trustcacerts -keystore $JAVA_HOME/lib/security/cacerts -file myCert.pem -alias myCert

With Java 5 (aka 1.5) or older, the -importcert option did not exist. It was called -import, but otherwise it's identical. So use

keytool -import -trustcacerts -keystore $JAVA_HOME/lib/security/cacerts -file myCert.pem -alias myCert

Additional options

  • You will be asked for the truststore password, The default password is changeit.
  • If you need to run the import unattended, you can add -storepass changeit -noprompt

Formats

keytool can import X.509 v1, v2, and v3 certificates, and PKCS#7 formatted certificate chains consisting of certificates of that type (P7B). The data to be imported must be provided

  • either in binary encoding format (DER)
  • or in printable encoding format (aka base64 encoded), enclosed in -----BEGIN and -----END lines (PEM)

Note: I'm not sure if certificate chains in PEM format really work.

Bonus script

I'm afraid, it's bash, so no solution for Windows users.

This simple script, created thanks to several useful questions and smart answers here on stackoverflow, checks the Java version and - if necessary - determines the correct keystore location, and it can import multiple certificates in one command. Note that you must pass the file pattern argument in single quotes (see usage).

addcerts.sh

#!/bin/bash

# Add custom root certificates to Java trust store

if [ "$#" -ne 1 ]; then
    SCRIPT=`basename "$0"`
    echo "Usage: $SCRIPT 'path/to/certs/*'"
    exit 1
fi

CERTFILES=$1    

JAVA_VERSION=`java -version 2>&1 | head -1 | cut -d'"' -f2 | sed '/^1\./s///' | cut -d'.' -f1`

if (( $JAVA_VERSION >= 9 )); then
    CACERTS="-cacerts"
else    
    # Check where cacerts are located
    # differs depending or jdk or jre installed
    if [ -d "$JAVA_HOME/jre" ]; then
        CACERTS="$JAVA_HOME/jre"
    else
        CACERTS="$JAVA_HOME"
    fi
    CACERTS="-keystore $CACERTS/lib/security/cacerts"   
fi      

# Now add certificates 
for CERTFILE in $CERTFILES; do
    # Remove path, then suffix to derive alias from filename
    ALIAS=${CERTFILE##*/}  
    ALIAS=${ALIAS%.*}
    $JAVA_HOME/bin/keytool -importcert -file "$CERTFILE" -alias "$ALIAS" $CACERTS -trustcacerts -storepass changeit -noprompt
    if [ $? -ne 0 ]; then
        echo "Failed to add $CERTFILE as $ALIAS to $CACERTS"
        exit 1
    fi  
done
Share:
442,685

Related videos on Youtube

sorin
Author by

sorin

Another geek still trying to decipher the meaning of “42”. It seems that amount his main interest are: online communities of practice and the way they evolve in time product design, simplicity in design and accessibility productivity and the way the IT solutions are impacting it

Updated on January 18, 2022

Comments

  • sorin
    sorin over 2 years

    I do want to import a self signed certificate into Java so any Java application that will try to establish a SSL connection will trust this certificate.

    So far, I managed to import it in

    keytool -import -trustcacerts -noprompt -storepass changeit -alias $REMHOST -file $REMHOST.pem
    keytool -import -trustcacerts -noprompt -keystore cacerts -storepass changeit -alias $REMHOST -file $REMHOST.pem
    

    Still, when I try to run HTTPSClient.class I still get:

    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    • Bruno
      Bruno almost 12 years
      I wouldn't necessarily rely on that code. Things like Security.addProvider(new com.sun.net.ssl.internal.ssl.Provider()) are completely unnecessary in the first part. The second doesn't do any cert verification. Try with a plain URLConnection to start with. Are you sure you've modified cacerts in lib/security of your JRE installation? Have you tried the trustmanager debugging option?
  • Alfabravo
    Alfabravo almost 12 years
    The main idea from this is not portecle but importing certificates into the right keystore.
  • Codezilla
    Codezilla over 9 years
    This worked, but my java was in a different location. My keystore was located at /usr/lib/jvm/java-openjdk/jre/lib/security/cacerts which I found by running ps -ef | grep java which told me my java was running from openjdk located at /usr/lib/jvm/java-openjdk/bin/java. Also, if this if for a webapp remember to restart. Thanks for the help!!
  • Bharat Darakh
    Bharat Darakh about 9 years
    Use this command :-> keytool -import -alias <alias> -keystore <cacerts_file> -trustcacerts -file <certificate_filename>
  • Xantix
    Xantix almost 9 years
    I haven't used portecle, but I found that Keystore Explorer works pretty well for Windows, Linux, (and it should work on OSX as well)
  • sdm
    sdm about 7 years
    Very helpful indeed. 2 very important things highlighted here. One is about importing in the right keystore. And another one is to make sure to restart in case of a webserver.
  • fabioresner
    fabioresner almost 7 years
    Just to complete, use $ sudo keytool -list -keystore cacerts | grep mycert to check if the import was successfull. Add -v parameter to list the certificates with more verbose.
  • The Gilbert Arenas Dagger
    The Gilbert Arenas Dagger about 6 years
    You will be prompted for the keystore password, the default is "changeit"
  • Ferrybig
    Ferrybig about 5 years
    In 2019, we can even get SSL certificates for free using services like Lets encrypt
  • traneHead
    traneHead about 5 years
    Just a FYI, works just as well on MacOS following the steps for Linux
  • Dragas
    Dragas almost 4 years
    "sudo keytool" NOPE
  • Tschenser
    Tschenser about 3 years
    At least in java 11 (sapmachine jre) the syntax changed slightly according to the manfile: keytool.exe -importcert -file <path to cer file> -cacerts -alias "<your alias>"
  • not2savvy
    not2savvy almost 3 years
    Note that you can use the -cacerts option instead of providing the path using -keystore. This is useful because the exact path varies depending on if you have installed a jdk or jre.
  • Muizz Mahdy
    Muizz Mahdy over 2 years
    @not2savvy Also note that the -cacerts option is only for Java 9 and above
  • not2savvy
    not2savvy over 2 years
    @MuizzMahdy That's right, see also my detailed answer here.
  • Cullub
    Cullub about 2 years
    /Applications/Xcode.app/Contents/Applications/Application Loader.app no longer exists -- is there a different place Xcode keeps its Java version?