How to properly import a selfsigned certificate into Java keystore that is available to all Java applications by default?
Solution 1
On Windows the easiest way is to use the program portecle.
- Download and install portecle.
- 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"));
- Copy the file JAVA_HOME\lib\security\cacerts to another folder.
- In Portecle click File > Open Keystore File
- Select the cacerts file
- Enter this password: changeit
- Click Tools > Import Trusted Certificate
- Browse for the file mycertificate.pem
- Click Import
- Click OK for the warning about the trust path.
- Click OK when it displays the details about the certificate.
- Click Yes to accept the certificate as trusted.
- When it asks for an alias click OK and click OK again when it says it has imported the certificate.
- Click save. Don’t forget this or the change is discarded.
- 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
Related videos on Youtube
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, 2022Comments
-
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 almost 12 yearsI 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 plainURLConnection
to start with. Are you sure you've modifiedcacerts
inlib/security
of your JRE installation? Have you tried thetrustmanager
debugging option?
-
-
Alfabravo almost 12 yearsThe main idea from this is not portecle but importing certificates into the right keystore.
-
Codezilla over 9 yearsThis 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 about 9 yearsUse this command :-> keytool -import -alias <alias> -keystore <cacerts_file> -trustcacerts -file <certificate_filename>
-
Xantix almost 9 yearsI 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 about 7 yearsVery 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 almost 7 yearsJust 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 about 6 yearsYou will be prompted for the keystore password, the default is "changeit"
-
Ferrybig about 5 yearsIn 2019, we can even get SSL certificates for free using services like Lets encrypt
-
traneHead about 5 yearsJust a FYI, works just as well on MacOS following the steps for Linux
-
Dragas almost 4 years"sudo keytool" NOPE
-
Tschenser about 3 yearsAt 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 almost 3 yearsNote 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 over 2 years@not2savvy Also note that the -cacerts option is only for Java 9 and above
-
not2savvy over 2 years@MuizzMahdy That's right, see also my detailed answer here.
-
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?