在Java客户端中接受服务器的自签名ssl证书

这看起来是一个标准问题,但我在任何地方都找不到明确的方向。

我有java代码试图连接到一个可能自签名(或过期)证书的服务器。代码报告以下错误:

[HttpMethodDirector] I/O exception (javax.net.ssl.SSLHandshakeException) caught
when processing request: sun.security.validator.ValidatorException: PKIX path
building failed: sun.security.provider.certpath.SunCertPathBuilderException:
unable to find valid certification path to requested target

根据我的理解,我必须使用keytool并告诉java允许此连接是OK的。

解决此问题的所有说明都假设我完全熟练使用keytool,例如

为服务器生成私有密钥并将其导入密钥存储库

有人能给我详细说明吗?

我正在运行unix,所以bash脚本将是最好的。

不确定这是否重要,但在jboss中执行的代码。

437854 次浏览

这里基本上有两个选择:将自签名证书添加到JVM信任存储库或将客户端配置为

选项1

从浏览器导出证书,并将其导入JVM信任库(以建立信任链):

<JAVA_HOME>\bin\keytool -import -v -trustcacerts
-alias server-alias -file server.cer
-keystore cacerts.jks -keypass changeit
-storepass changeit

选项2

禁用证书验证(代码来自例子得宝):

// Create a trust manager that does not validate certificate chains
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}
public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType) {
}
}
};


// Install the all-trusting trust manager
try {
SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
} catch (GeneralSecurityException e) {
}
// Now you can access an https URL without having the certificate in the truststore
try {
URL url = new URL("https://hostname/index.html");
} catch (MalformedURLException e) {
}

注意我完全不推荐选择#2.;禁用信任管理器会破坏SSL的某些部分,使您容易受到中间人攻击。首选选项1,或者更好,让服务器使用“real"由知名核证机关签署的证书。

如果“他们”使用自签名证书,则由他们采取必要的步骤使他们的服务器可用。具体来说,这意味着以一种值得信赖的方式离线向您提供他们的证书。所以让他们这么做。然后,按照JSSE参考指南中的描述,使用keytool将其导入到您的信任库中。不要想这里发布的不安全的TrustManager。

编辑为了十七岁(!)的反对者和下面的许多评论者的利益,他们显然没有真正读过我在这里写的东西,这是不< em > < / em >对自签名证书的悲叹。自签名证书当正确执行时。 但是,没有问题,实现它们的正确方法是让证书交付安全地通过离线过程,,而不是通过未经身份验证的通道,它们将被用于身份验证。这是显而易见的吗?从拥有数千家分支机构的银行到我自己的公司,我曾经工作过的每一个有安全意识的组织都很明显地知道这一点。信任所有证书的客户端代码基“解决方案”是根据事实本身不安全的,包括由绝对任何人或任何将自己设置为CA的任意机构签署的自签名证书。它只是在玩安全游戏。这毫无意义。你正在进行一场私人的,防篡改,防回复,防注射的对话,和…别人。任何人。一个男人在中间。一个冒名顶替者。任何人。你也可以只使用纯文本。

我将此问题追查到一个证书提供程序,该证书提供程序不属于JDK 8u74的默认JVM受信任主机。提供者是www.identrust.com,但那不是我试图连接到的域。该域已从该提供者获得其证书。参见交叉根覆盖信任JDK/JRE中的默认列表吗?——向下读几个条目。也可以参见哪些浏览器和操作系统支持Let 's Encrypt

因此,为了连接到我感兴趣的域,它有一个由identrust.com颁发的证书,我执行了以下步骤。基本上,我必须获得identrust.com (DST Root CA X3)证书才能被JVM信任。我可以使用Apache HttpComponents 4.5这样做:

1:从indettrust中证书链下载说明获取证书。单击DST根CA X3链接。

2:保存到“DST Root CA X3.pem”文件中。确保在文件的开头和结尾添加行“-----BEGIN CERTIFICATE-----”和“-----END CERTIFICATE-----”。

3:创建java的keystore文件cacerts。JKS,命令如下:

keytool -import -v -trustcacerts -alias IdenTrust -keypass yourpassword -file dst_root_ca_x3.pem -keystore cacerts.jks -storepass yourpassword

4:复制生成的cacerts。将JKS密钥存储库保存到java/(maven)应用程序的资源目录中。

5:使用以下代码加载该文件,并将其附加到Apache 4.5 HttpClient。这将解决所有拥有indetrust.com util颁发证书的域的问题,oracle将证书包含到JRE默认密钥库中。

SSLContext sslcontext = SSLContexts.custom()
.loadTrustMaterial(new File(CalRestClient.class.getResource("/cacerts.jks").getFile()), "yourpasword".toCharArray(),
new TrustSelfSignedStrategy())
.build();
// Allow TLSv1 protocol only
SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
sslcontext,
new String[] { "TLSv1" },
null,
SSLConnectionSocketFactory.getDefaultHostnameVerifier());
CloseableHttpClient httpclient = HttpClients.custom()
.setSSLSocketFactory(sslsf)
.build();

当项目构建时,cacerts。JKS将被复制到类路径中并从那里加载。我没有,在这个时间点上,测试其他ssl站点,但如果上面的代码“链”在这个证书,那么他们也会工作,但是,我不知道。

参考:自定义SSL上下文如何使用Java HttpsURLConnection接受自签名证书?

而不是设置默认的套接字工厂(这在我看来是一件坏事)- yhis只会影响当前连接,而不是你试图打开的每一个SSL连接:

URLConnection connection = url.openConnection();
// JMD - this is a better way to do it that doesn't override the default SSL factory.
if (connection instanceof HttpsURLConnection)
{
HttpsURLConnection conHttps = (HttpsURLConnection) connection;
// Set up a Trust all manager
TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager()
{


public java.security.cert.X509Certificate[] getAcceptedIssuers()
{
return null;
}


public void checkClientTrusted(
java.security.cert.X509Certificate[] certs, String authType)
{
}


public void checkServerTrusted(
java.security.cert.X509Certificate[] certs, String authType)
{
}
} };


// Get a new SSL context
SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
// Set our connection to use this SSL context, with the "Trust all" manager in place.
conHttps.setSSLSocketFactory(sc.getSocketFactory());
// Also force it to trust all hosts
HostnameVerifier allHostsValid = new HostnameVerifier() {
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
// and set the hostname verifier.
conHttps.setHostnameVerifier(allHostsValid);
}
InputStream stream = connection.getInputStream();

信任所有SSL证书:- 如果希望在测试服务器上进行测试,可以绕过SSL。 但是不要将此代码用于生产。< / p >

public static class NukeSSLCerts {
protected static final String TAG = "NukeSSLCerts";


public static void nuke() {
try {
TrustManager[] trustAllCerts = new TrustManager[] {
new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {
X509Certificate[] myTrustedAnchors = new X509Certificate[0];
return myTrustedAnchors;
}


@Override
public void checkClientTrusted(X509Certificate[] certs, String authType) {}


@Override
public void checkServerTrusted(X509Certificate[] certs, String authType) {}
}
};


SSLContext sc = SSLContext.getInstance("SSL");
sc.init(null, trustAllCerts, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
} catch (Exception e) {
}
}

请在Activity或应用程序类的onCreate()函数中调用此函数。

NukeSSLCerts.nuke();

这可以用于Android的Volley。

Apache HttpClient 4.5支持接受自签名证书:

SSLContext sslContext = SSLContexts.custom()
.loadTrustMaterial(new TrustSelfSignedStrategy())
.build();
SSLConnectionSocketFactory socketFactory =
new SSLConnectionSocketFactory(sslContext);
Registry<ConnectionSocketFactory> reg =
RegistryBuilder.<ConnectionSocketFactory>create()
.register("https", socketFactory)
.build();
HttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(reg);
CloseableHttpClient httpClient = HttpClients.custom()
.setConnectionManager(cm)
.build();
HttpGet httpGet = new HttpGet(url);
CloseableHttpResponse sslResponse = httpClient.execute(httpGet);

这将构建一个SSL套接字工厂,该工厂将使用TrustSelfSignedStrategy,将其注册到自定义连接管理器,然后使用该连接管理器执行HTTP GET。

我同意那些高呼“不要在生产环境中这样做”的人,但是在生产环境之外接受自签名证书是有用例的;我们在自动化集成测试中使用它们,因此即使不在生产硬件上运行,我们也在使用SSL(就像在生产中一样)。

接受的答案是好的,但我想添加一些东西,因为我在Mac上使用IntelliJ,无法使用JAVA_HOME路径变量让它工作。

事实证明,从IntelliJ运行应用程序时,Java Home是不同的。

要找出它的确切位置,你可以只执行System.getProperty("java.home"),因为这是可信证书的读取位置。

有一个更好的替代信任所有证书的方法:创建一个TrustStore,它专门信任一个给定的证书,并使用它来创建一个SSLContext,从中获取SSLSocketFactory来设置在HttpsURLConnection上。以下是完整的代码:

File crtFile = new File("server.crt");
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(crtFile));
// Or if the crt-file is packaged into a jar file:
// CertificateFactory.getInstance("X.509").generateCertificate(this.class.getClassLoader().getResourceAsStream("server.crt"));




KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server", certificate);


TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);


SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);


HttpsURLConnection connection = (HttpsURLConnection) new URL(url).openConnection();
connection.setSSLSocketFactory(sslContext.getSocketFactory());

您也可以直接从文件加载KeyStore,或者从任何受信任的来源检索X.509证书。

注意,在这段代码中,cacerts中的证书将不会被使用。这个特殊的HttpsURLConnection将只信任这个特定的证书。

这不是解决全部问题的解决方案,但是oracle有关于如何使用这个keytool的详细文档。这解释了如何

  1. 使用keytool。
  2. 使用keytool生成证书/自签名证书。
  3. 将生成的证书导入Java客户端。

https://docs.oracle.com/cd/E54932_01/doc.705/e54936/cssg_create_ssl_cert.htm#CSVSG178

在RHEL上,您可以从RHEL 6的新版本开始使用update-ca-trust,而不是像上面的注释所建议的那样使用keytool。您需要拥有pem格式的证书。然后

trust anchor <cert.pem>

编辑/etc/pki/ca-trust/source/cert.P11-kit,将“证书类别:other-entry”修改为“证书类别:authority”。(或使用sed在脚本中完成此操作。)然后做

update-ca-trust

几点注意事项:

  • 我在我的RHEL 6服务器上找不到“信任”,yum也没有提供安装它。我最终在RHEL 7服务器上使用它,并复制了.p11-kit文件。
  • 为了让它为你工作,你可能需要执行update-ca-trust enable。这将用一个指向/etc/pki/ca-trust/extract /java/cacerts的符号链接替换/etc/pki/java/cacerts(所以你可能想先支持前者。)
  • 如果您的java客户端使用存储在其他位置的cacerts,则需要手动将其替换为到/etc/pki/ca-trust/extract /java/cacerts的符号链接,或者将其替换为该文件。

我有一个问题,我正在传递一个URL到一个库,它正在调用url.openConnection();,我改编了jon-daniel的答案,

public class TrustHostUrlStreamHandler extends URLStreamHandler {


private static final Logger LOG = LoggerFactory.getLogger(TrustHostUrlStreamHandler.class);


@Override
protected URLConnection openConnection(final URL url) throws IOException {


final URLConnection urlConnection = new URL(url.getProtocol(), url.getHost(), url.getPort(), url.getFile()).openConnection();


// adapated from
// https://stackoverflow.com/questions/2893819/accept-servers-self-signed-ssl-certificate-in-java-client
if (urlConnection instanceof HttpsURLConnection) {
final HttpsURLConnection conHttps = (HttpsURLConnection) urlConnection;


try {
// Set up a Trust all manager
final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {


@Override
public java.security.cert.X509Certificate[] getAcceptedIssuers() {
return null;
}


@Override
public void checkClientTrusted(final java.security.cert.X509Certificate[] certs, final String authType) {
}


@Override
public void checkServerTrusted(final java.security.cert.X509Certificate[] certs, final String authType) {
}
} };


// Get a new SSL context
final SSLContext sc = SSLContext.getInstance("TLSv1.2");
sc.init(null, trustAllCerts, new java.security.SecureRandom());
// Set our connection to use this SSL context, with the "Trust all" manager in place.
conHttps.setSSLSocketFactory(sc.getSocketFactory());
// Also force it to trust all hosts
final HostnameVerifier allHostsValid = new HostnameVerifier() {
@Override
public boolean verify(final String hostname, final SSLSession session) {
return true;
}
};


// and set the hostname verifier.
conHttps.setHostnameVerifier(allHostsValid);


} catch (final NoSuchAlgorithmException e) {
LOG.warn("Failed to override URLConnection.", e);
} catch (final KeyManagementException e) {
LOG.warn("Failed to override URLConnection.", e);
}


} else {
LOG.warn("Failed to override URLConnection. Incorrect type: {}", urlConnection.getClass().getName());
}


return urlConnection;
}


}

使用这个类可以创建一个新的URL:

trustedUrl = new URL(new URL(originalUrl), "", new TrustHostUrlStreamHandler());
trustedUrl.openConnection();

这样做的好处是它是本地化的,并且不会替换默认的URL.openConnection

接受的答案需要选项3

< p >也 选项2是可怕的。绝对不应该使用它(特别是在生产中),因为它提供了一种虚假的安全感。

选项3

使用自签名证书进行Https连接。

这里有一个例子:

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManagerFactory;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.KeyStore;


/*
* Use a SSLSocket to send a HTTP GET request and read the response from an HTTPS server.
* It assumes that the client is not behind a proxy/firewall
*/


public class SSLSocketClientCert
{
private static final String[] useProtocols = new String[] {"TLSv1.2"};
public static void main(String[] args) throws Exception
{
URL inputUrl = null;
String certFile = null;
if(args.length < 1)
{
System.out.println("Usage: " + SSLSocketClient.class.getName() + " <url>");
System.exit(1);
}
if(args.length == 1)
{
inputUrl = new URL(args[0]);
}
else
{
inputUrl = new URL(args[0]);
certFile = args[1];
}
SSLSocket sslSocket = null;
PrintWriter outWriter = null;
BufferedReader inReader = null;
try
{
SSLSocketFactory sslSocketFactory = getSSLSocketFactory(certFile);


sslSocket = (SSLSocket) sslSocketFactory.createSocket(inputUrl.getHost(), inputUrl.getPort() == -1 ? inputUrl.getDefaultPort() : inputUrl.getPort());
String[] enabledProtocols = sslSocket.getEnabledProtocols();
System.out.println("Enabled Protocols: ");
for(String enabledProtocol : enabledProtocols) System.out.println("\t" + enabledProtocol);


String[] supportedProtocols = sslSocket.getSupportedProtocols();
System.out.println("Supported Protocols: ");
for(String supportedProtocol : supportedProtocols) System.out.println("\t" + supportedProtocol + ", ");


sslSocket.setEnabledProtocols(useProtocols);


/*
* Before any data transmission, the SSL socket needs to do an SSL handshake.
* We manually initiate the handshake so that we can see/catch any SSLExceptions.
* The handshake would automatically  be initiated by writing & flushing data but
* then the PrintWriter would catch all IOExceptions (including SSLExceptions),
* set an internal error flag, and then return without rethrowing the exception.
*
* This means any error messages are lost, which causes problems here because
* the only way to tell there was an error is to call PrintWriter.checkError().
*/
sslSocket.startHandshake();
outWriter = sendRequest(sslSocket, inputUrl);
readResponse(sslSocket);
closeAll(sslSocket, outWriter, inReader);
}
catch(Exception e)
{
e.printStackTrace();
}
finally
{
closeAll(sslSocket, outWriter, inReader);
}
}


private static PrintWriter sendRequest(SSLSocket sslSocket, URL inputUrl) throws IOException
{
PrintWriter outWriter = new PrintWriter(new BufferedWriter(new OutputStreamWriter(sslSocket.getOutputStream())));
outWriter.println("GET " + inputUrl.getPath() + " HTTP/1.1");
outWriter.println("Host: " + inputUrl.getHost());
outWriter.println("Connection: Close");
outWriter.println();
outWriter.flush();
if(outWriter.checkError())        // Check for any PrintWriter errors
System.out.println("SSLSocketClient: PrintWriter error");
return outWriter;
}


private static void readResponse(SSLSocket sslSocket) throws IOException
{
BufferedReader inReader = new BufferedReader(new InputStreamReader(sslSocket.getInputStream()));
String inputLine;
while((inputLine = inReader.readLine()) != null)
System.out.println(inputLine);
}


// Terminate all streams
private static void closeAll(SSLSocket sslSocket, PrintWriter outWriter, BufferedReader inReader) throws IOException
{
if(sslSocket != null) sslSocket.close();
if(outWriter != null) outWriter.close();
if(inReader != null) inReader.close();
}


// Create an SSLSocketFactory based on the certificate if it is available, otherwise use the JVM default certs
public static SSLSocketFactory getSSLSocketFactory(String certFile)
throws CertificateException, KeyStoreException, IOException, NoSuchAlgorithmException, KeyManagementException
{
if (certFile == null) return (SSLSocketFactory) SSLSocketFactory.getDefault();
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(new FileInputStream(new File(certFile)));


KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(null, null);
keyStore.setCertificateEntry("server", certificate);


TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);


SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);


return sslContext.getSocketFactory();
}
}


用浏览器从目标页面下载自签名证书,并将其添加到默认存储,默认密码:

keytool -import -v -trustcacerts -file selfsigned.crt -alias myserver -keystore /etc/alternatives/jre/lib/security/cacerts -storepass changeit

使用文件$JAVA_HOME/jre/lib/security/cacerts,我这里的例子来自Oracle linux 7.7。

Kotlin中的变体

    @SuppressLint("CustomX509TrustManager", "TrustAllX509TrustManager")
fun ignoreSsl() {
val trustAllCerts: Array<TrustManager> = arrayOf(
object : X509TrustManager {
override fun getAcceptedIssuers(): Array<X509Certificate>? = null
override fun checkClientTrusted(certs: Array<X509Certificate?>?, authType: String?) {}
override fun checkServerTrusted(certs: Array<X509Certificate?>?, authType: String?) {}
})
val sc = SSLContext.getInstance("SSL")
sc.init(null, trustAllCerts, SecureRandom())
HttpsURLConnection.setDefaultSSLSocketFactory(sc.socketFactory)
}

姗姗来迟,您可以通过在RestTemplate级别禁用它来实现。 请注意,这个TrustStrategy将信任所有证书,并且您使用NoopHostnameVerifier ()禁用了主机名验证

public RestTemplate getRestTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
TrustStrategy acceptingTrustStrategy = (x509Certificates, s) -> true;
SSLContext sslContext = org.apache.http.ssl.SSLContexts.custom().loadTrustMaterial(null, acceptingTrustStrategy).build();
SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(csf).build();
HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
requestFactory.setHttpClient(httpClient);
return new RestTemplate(requestFactory);
}

受下面annser的启发,我找到了一种信任自签名CA并保持信任默认CA的方法。

    File file = new File(System.getProperty("java.home"), "lib/security/cacerts");
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
keyStore.load(new FileInputStream(file), "changeit".toCharArray());




InputStream resourceAsStream = getClass().getClassLoader().getResourceAsStream("testCer.cer");
Certificate certificate = CertificateFactory.getInstance("X.509").generateCertificate(resourceAsStream);
keyStore.setCertificateEntry("my-server-alias", certificate);


TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);


SSLContext sslContext = SSLContexts.createDefault();
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);




// check domain
// SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);


// not check domain
SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,
new String[]{"TLSv1","TLSv1.1","TLSv1.2","SSLv3"},null, NoopHostnameVerifier.INSTANCE);


CloseableHttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
factory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(factory);

这是第一个有太多答案的古老问题,我认为我可以提供一个更有用的想法:如果服务器所有者拒绝以可信任的方式离线向我提供他们的证书,我会使用这个选项:

  1. 从服务器本身检索证书(使用命令行工具而不是浏览器)
  2. 将该证书添加到java密钥存储库以信任它。将显示证书的详细信息,以验证它。
# HOSTNAME_PORT is the host that you want to connect to - example: HOSTNAME_PORT=stackoverflow.com:443
HOSTNAME_PORT=hostname_part_of_url_without_https:port


# whatever you want to call the key within the Java key store
MY_KEY_ALIAS=the_key_I_added_with_help_from_stackoverflow


openssl s_client -showcerts -connect $HOSTNAME_PORT </dev/null 2>/dev/null|openssl x509 -outform PEM >mycertfile.pem
sudo keytool -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts/pki/java/cacerts -storepass changeit -importcert -alias $MY_KEY_ALIAS -file mycertfile.pem


在提示时输入yes,但只有当你真的信任显示给你的证书并想要将其添加到计算机的全局java密钥存储库时才可以。

< p >供参考:$JAVA_HOME/jre/lib/security/cacerts 在我的情况下(CentOS 7)指向: /etc/pki/java/cacerts < / p >

我遇到了这个问题,因为依赖项来自maven repo,它是我的本地服务器,具有自签名证书和自签名CA证书。为了解决这个错误,我必须运行以下两个命令:

<my_java_install_dir>\bin\keytool.exe -importcert -file <my-self-signed-CA-cert>.crt -keystore <my_java_install_dir>\lib\security\cacerts -alias my-CA-cert

然后

<my_java_install_dir>\jdk11.0.14_10\bin\keytool.exe -importcert -file <my-self-signed-maven-repo-cert>.crt -keystore <my_java_install_dir>\lib\security\cacerts -alias my-maven-repo-cert