如何将自签名证书正确导入Java密钥库,默认情况下可供所有Java应用程序使用?

问题

我确实想将自签名证书导入Java,因此任何尝试建立SSL连接的Java应用程序都会信任此证书。

到目前为止,我设法导入它

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

不过,当我尝试运行HTTPSClient.class时,我仍然得到:

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

#1 热门回答(166 赞)

在Windows上,最简单的方法是使用程序portecle

  • 下载并安装portecle。
  • 首先100%确定你知道正在使用哪个JRE或JDK来运行你的程序。在64位Windows 7上可能会有相当多的JRE。 Process Explorer可以帮助你,或者你可以使用:System.out.println(System.getProperty("java.home"));
  • 将文件JAVA_HOME \ lib \ security \ cacerts复制到另一个文件夹。
  • 在Portecle中,单击"文件">"打开密钥库文件"
  • 选择cacerts文件
  • 输入此密码:changeit
  • 单击工具>导入可信证书
  • 浏览文件mycertificate.pem
  • 单击"导入"
  • 单击"确定"以获取有关信任路径的警告。
  • 显示有关证书的详细信息时,单击"确定"。
  • 单击"是"将证书接受为受信任。
  • 当它要求别名时单击"确定",并在说明已导入证书时再次单击"确定"。
  • 单击"保存"。不要忘记这一点或更改被丢弃。
  • 将文件cacerts复制回找到它的位置。
    在Linux上:
    你可以从已经使用它的Web服务器下载SSL证书,如下所示:
$ echo -n | openssl s_client -connect www.example.com:443 | \
   sed -ne '/-BEGIN CERTIFICATE-/,/-END CERTIFICATE-/p' > /tmp/examplecert.crt

(可选)验证证书信息:

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

将证书导入Java cacerts密钥库:

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

编辑:

这些天我们不必经常向密钥库添加证书,因为你可以从ssls.com获得每年5美元的证书。以防这是你的选择。


#2 热门回答(27 赞)

我最终编写了一个将证书添加到密钥库的小脚本,因此使用起来更加容易。

你可以从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

----

## #3 热门回答(23 赞)

```java
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"