Unable to find valid certification path to requested target - error even after cert imported
我有一个Java客户端试图用一个自签名证书访问一个服务器。
当我尝试将邮件发送到服务器时,会出现以下错误:
unable to find valid certification path to requested target
在对这个问题做了一些研究之后,我做了以下的工作。
我看到证书在。
我仍然收到同样的错误。
我有一种感觉,这是因为我的Glassfish并没有真正阅读我修改过的cacert文件,但可能是其他文件。
你们中有谁有这个问题,能把我推向正确的方向吗?
不幸的是,它可能有很多东西,而且很多应用服务器和其他Java"包装器"都倾向于玩属性,而他们自己的"钥匙链"则不需要。所以它可能在寻找完全不同的东西。
缺少桁架-我会尝试:
1 | java -Djavax.net.debug=all -Djavax.net.ssl.trustStore=trustStore ... |
看看是否有帮助。除了"全部"之外,还可以将其设置为"ssl"、"密钥管理器"和"信任管理器",这在您的情况下可能会有所帮助。将其设置为"帮助"将在大多数平台上列出类似下面的内容。
无论如何-确保您完全理解密钥存储库(其中您有私钥和证书证明您自己的身份)和信任存储库(决定您信任的人)之间的区别-以及您自己的身份也有一个到根的"信任链"这一事实-它与您需要的任何到根的链分离找出你信任的人。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | all turn on all debugging ssl turn on ssl debugging The following can be used with ssl: record enable per-record tracing handshake print each handshake message keygen print key generation data session print session activity defaultctx print default SSL initialization sslctx print SSLContext tracing sessioncache print session cache tracing keymanager print key manager tracing trustmanager print trust manager tracing pluggability print pluggability tracing handshake debugging can be widened with: data hex dump of each handshake message verbose verbose handshake message printing record debugging can be widened with: plaintext hex dump of record plaintext packet print raw SSL/TLS packets |
来源:请参阅http://download.oracle.com/javase/1.5.0/docs/guide/security/jsse/jsserefguide.html调试
以下是解决方案,请按照以下链接逐步操作:
http://www.mkyong.com/webservices/jax-ws/suncertpathbuilderexception-unable-to-find-valid-certification-path-to-requested-target/
Java文件:从博客中丢失的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 | /* * Copyright 2006 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Sun Microsystems nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS"AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ import java.io.*; import java.net.URL; import java.security.*; import java.security.cert.*; import javax.net.ssl.*; public class InstallCert { public static void main(String[] args) throws Exception { String host; int port; char[] passphrase; if ((args.length == 1) || (args.length == 2)) { String[] c = args[0].split(":"); host = c[0]; port = (c.length == 1) ? 443 : Integer.parseInt(c[1]); String p = (args.length == 1) ?"changeit" : args[1]; passphrase = p.toCharArray(); } else { System.out.println("Usage: java InstallCert <host>[:port] [passphrase]"); return; } File file = new File("jssecacerts"); if (file.isFile() == false) { char SEP = File.separatorChar; File dir = new File(System.getProperty("java.home") + SEP +"lib" + SEP +"security"); file = new File(dir,"jssecacerts"); if (file.isFile() == false) { file = new File(dir,"cacerts"); } } System.out.println("Loading KeyStore" + file +"..."); InputStream in = new FileInputStream(file); KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType()); ks.load(in, passphrase); in.close(); SSLContext context = SSLContext.getInstance("TLS"); TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(ks); X509TrustManager defaultTrustManager = (X509TrustManager)tmf.getTrustManagers()[0]; SavingTrustManager tm = new SavingTrustManager(defaultTrustManager); context.init(null, new TrustManager[] {tm}, null); SSLSocketFactory factory = context.getSocketFactory(); System.out.println("Opening connection to" + host +":" + port +"..."); SSLSocket socket = (SSLSocket)factory.createSocket(host, port); socket.setSoTimeout(10000); try { System.out.println("Starting SSL handshake..."); socket.startHandshake(); socket.close(); System.out.println(); System.out.println("No errors, certificate is already trusted"); } catch (SSLException e) { System.out.println(); e.printStackTrace(System.out); } X509Certificate[] chain = tm.chain; if (chain == null) { System.out.println("Could not obtain server certificate chain"); return; } BufferedReader reader = new BufferedReader(new InputStreamReader(System.in)); System.out.println(); System.out.println("Server sent" + chain.length +" certificate(s):"); System.out.println(); MessageDigest sha1 = MessageDigest.getInstance("SHA1"); MessageDigest md5 = MessageDigest.getInstance("MD5"); for (int i = 0; i < chain.length; i++) { X509Certificate cert = chain[i]; System.out.println ("" + (i + 1) +" Subject" + cert.getSubjectDN()); System.out.println(" Issuer " + cert.getIssuerDN()); sha1.update(cert.getEncoded()); System.out.println(" sha1 " + toHexString(sha1.digest())); md5.update(cert.getEncoded()); System.out.println(" md5 " + toHexString(md5.digest())); System.out.println(); } System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]"); String line = reader.readLine().trim(); int k; try { k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1; } catch (NumberFormatException e) { System.out.println("KeyStore not changed"); return; } X509Certificate cert = chain[k]; String alias = host +"-" + (k + 1); ks.setCertificateEntry(alias, cert); OutputStream out = new FileOutputStream("jssecacerts"); ks.store(out, passphrase); out.close(); System.out.println(); System.out.println(cert); System.out.println(); System.out.println ("Added certificate to keystore 'jssecacerts' using alias '" + alias +"'"); } private static final char[] HEXDIGITS ="0123456789abcdef".toCharArray(); private static String toHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(bytes.length * 3); for (int b : bytes) { b &= 0xff; sb.append(HEXDIGITS[b >> 4]); sb.append(HEXDIGITS[b & 15]); sb.append(' '); } return sb.toString(); } private static class SavingTrustManager implements X509TrustManager { private final X509TrustManager tm; private X509Certificate[] chain; SavingTrustManager(X509TrustManager tm) { this.tm = tm; } public X509Certificate[] getAcceptedIssuers() { throw new UnsupportedOperationException(); } public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException { throw new UnsupportedOperationException(); } public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException { this.chain = chain; tm.checkServerTrusted(chain, authType); } } } |
您需要配置JSSE系统属性,特别是指向客户机证书存储。
通过命令行:
1 | java -Djavax.net.ssl.trustStore=truststores/client.ts com.progress.Client |
或通过Java代码:
1 2 3 4 5 6 7 8 9 | import java.util.Properties; ... Properties systemProps = System.getProperties(); systemProps.put("javax.net.ssl.keyStorePassword","passwordForKeystore"); systemProps.put("javax.net.ssl.keyStore","pathToKeystore.ks"); systemProps.put("javax.net.ssl.trustStore","pathToTruststore.ts"); systemProps.put("javax.net.ssl.trustStorePassword","passwordForTrustStore"); System.setProperties(systemProps); ... |
有关更多信息,请参阅RedHat网站上的详细信息。
(从我的其他回复中转发)从Java软件分发中使用CLI实用密钥工具进行导入(信任!)需要的证书
Sample:
从cli change dir到jrein
检查密钥库(在jrein目录中找到的文件)keytool-list-keystore..libsecuritycacerts密码已更改
从需要的服务器下载并保存链中的所有证书。
添加证书(在需要删除文件"..libsecuritycacerts"上的"read-only"属性之前),运行:keytool-alias replace_to_any_uniq_name-import-keystore..libsecuritycacerts-file"r:
oot.crt"
我不小心发现了这么简单的小费。其他解决方案需要使用安装Curt.java和JDK。
资料来源:http://www.java-samples.com/showtutorial.php?TutoRalID=210
我对SBT也有同样的问题。
它试图通过ssl从repo1.maven.org获取依赖项
但表示"无法找到请求的目标URL的有效认证路径"。
所以我跟着这个帖子仍然无法验证连接。
因此,我阅读了相关内容,发现根证书不够,正如文章所建议的那样,因此-
对我有用的是将中间CA证书导入密钥库。
我实际上把所有的证书都加在了链子里,它很有魅力。
从JDK 8迁移到JDK 10时的解决方案
- 证书真的不一样
- JDK 10有80个,而JDK 8有151个
- JDK 10最近增加了
certs 。- https://dzone.com/articles/openjdk-10-now-includes-root-ca-certificates
- http://openjdk.java.net/jeps/319
JDK 10
1 2 3 4 5 6 | root@c339504909345:/opt/jdk-minimal/jre/lib/security # keytool -cacerts -list Enter keystore password: Keystore type: JKS Keystore provider: SUN Your keystore contains 80 entries |
JDK 8
1 2 3 4 5 6 | root@c39596768075:/usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts # keytool -cacerts -list Enter keystore password: Keystore type: JKS Keystore provider: SUN Your keystore contains 151 entries |
修复步骤
- 我删除了JDK 10证书,并将其替换为JDK 8
- 因为我正在构建Docker图像,所以我可以使用多阶段构建快速实现这一点。
- 我正在使用
jlink 作为/opt/jdk/bin/jlink \ 构建一个最小的JRE。
--module-path /opt/jdk/jmods...
- 我正在使用
下面是不同的路径和命令序列…
1 2 3 4 5 6 | # Java 8 COPY --from=marcellodesales-springboot-builder-jdk8 /usr/lib/jvm/java-8-openjdk-amd64/jre/lib/security/cacerts /etc/ssl/certs/java/cacerts # Java 10 RUN rm -f /opt/jdk-minimal/jre/lib/security/cacerts RUN ln -s /etc/ssl/certs/java/cacerts /opt/jdk-minimal/jre/lib/security/cacerts |
我正在做一个关于REST Web服务的教程,在www. udimy.com(REST JavaWeb服务)上。教程中的示例说,为了拥有SSL,我们必须在Eclipse"客户机"项目中有一个名为"信任存储"的文件夹,该文件夹应包含一个"密钥存储"文件(我们有一个"客户机"项目来调用该服务,以及包含其余Web服务的"服务"项目-在同一Eclipse工作区中有两个项目,一个是客户机,另一个是客户机服务)。为了简单起见,他们说要从我们使用的glassfish应用服务器(glassfishdomainsdomain1configkeystore.jsk)中复制"keystore.jks",并将其放入我在客户机项目中创建的"trust-store"文件夹中。这似乎有道理:服务器密钥存储区中的自签名证书将与客户机信任存储区中的证书相对应。现在,这样做,我得到了原始帖子提到的错误。我在谷歌上搜索了这个信息,并阅读到错误是由于客户端上的"keystore.jks"文件不包含可信/签名证书,它找到的证书是自签名的。
为了保持清晰,让我说,据我所知,"keystore.jsk"包含自签名证书,"ca certs.jks"文件包含CA证书(由CA签名)。"keystore.jks"是"keystore","cacerts.jks"是"信任库"。正如上面评论者所说的"bruno","keystore.jks"是本地的,"cacerts.jks"是远程客户机的。
所以,我对自己说,嘿,Glassfish也有"cacerts.jks"文件,这是Glassfish的信任库文件。jsk应该包含CA证书。显然,我需要我的信任存储文件夹包含至少有一个CA证书的密钥存储文件。因此,我尝试将"cacerts.jks"文件放在我创建的"trust-store"文件夹中的客户机项目上,并将VM属性更改为指向"cacerts.jks"而不是"keystore.jks"。这样就消除了错误。我想只需要一张证书就行了。
这可能不适合于生产,甚至不适合于开发,而不仅仅是工作。例如,您可以使用"keytool"命令将CA证书添加到客户机中的"keystore.jks"文件中。但无论如何,希望这至少缩小了可能导致错误的场景。
另外:我的方法似乎对客户机很有用(服务器证书添加到客户机信任存储),上面解析原始日志的注释对服务器很有用(客户证书添加到服务器信任存储)。干杯。
Eclipse项目设置:
- Myclipse项目
- SRC
- 测试
- JRE系统库
- …
- 信托商店-CACERT.JKSK-SkyStudioJKS
myclientproject.java文件中的代码段:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | static { // Setup the trustStore location and password System.setProperty("javax.net.ssl.trustStore","trust_store/cacerts.jks"); // comment out below line System.setProperty("javax.net.ssl.trustStore","trust_store/keystore.jks"); System.setProperty("javax.net.ssl.trustStorePassword","changeit"); //System.setProperty("javax.net.debug","all"); // for localhost testing only javax.net.ssl.HttpsURLConnection.setDefaultHostnameVerifier(new javax.net.ssl.HostnameVerifier() { public boolean verify(String hostname, javax.net.ssl.SSLSession sslSession) { return hostname.equals("localhost"); } }); } |
检查文件
解决方案:将真正的cacerts文件(您可以从另一个jdk中复制)复制到
我的问题是一个云访问安全代理netskope通过软件更新安装在我的笔记本电脑上。这改变了证书链,在导入整个Calcts密钥库后,我仍然无法通过Java客户端连接到服务器。我禁用了Netskope并成功连接。
假设您使用pom.xml中的类路径变量,如$java_home。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | <target> <property name="compile_classpath" refid="maven.compile.classpath"/> <property name="runtime_classpath" refid="maven.runtime.classpath"/> <property name="test_classpath" refid="maven.test.classpath"/> <property name="plugin_classpath" refid="maven.plugin.classpath"/> <property name="jaxb-api.jar" value="${maven.dependency.javax.xml.bind.jaxb-api.jar.path}"/> <property name="project_home" value="${PROJECT_HOME}"/> <property name="java_home" value="${JAVA_HOME}"/> <property name="ant_home" value="${ANT_HOME}"/> <property name="common_home" value="${COMMON_HOME}"/> <property name="JAXP_HOME" value="${common_home}/lib"/> <property name="ejfw_home" value="${PROJECT_HOME}/lib"/> <property name="weblogic_home" value="${WL_HOME}"/> <property name="fw_home" value="${FW_HOME}"/> <property name="env" value="${BUILDENV}"/> <property name="tokenfile" value="${BUILDENV}${BUILDENV_S2S}.properties"/> |
在目标中,添加类路径变量。例如,-唐太家,-德贾瓦家
1 | clean install -e -DPROJECT_HOME=..... -DANT_HOME=C:\bea1036\modules\org.apache.ant_1.7.1 -DJAVA_HOME=C:\bea1036\jdk160_31 |