2012-02-09 96 views
118

Possible Duplicate:
PKIX path building failed: unable to find valid certification path to requested target无法找到有效的认证路径要求的目标 - 甚至错误的证书后,进口

我有一个Java客户端尝试用自签名证书访问服务器。

当我尝试发布到服务器上,我得到以下错误:

unable to find valid certification path to requested target

做完对这个问题的一些研究,然后我做了以下。

  1. 将我的服务器域名保存为root.cer文件。
  2. 在我的Glassfish服务器的JRE中,我运行了这个: keytool -import -alias示例-keystore cacerts -file root.cer。
  3. 要检查证书是否已成功添加到我的cacert中,我这样做了: keytool -list -v -keystore cacerts 我可以看到证书存在。
  4. 然后我重新启动了Glassfish并退出了'发布'。

我仍然得到相同的错误。

我有一种感觉,这是因为我的Glassfish实际上并没有阅读我已经修改过的cacert文件,但也许还有一些。

有没有人有这个问题,可以推动我在正确的方向吗?

+1

只是为了澄清:“我有一个Java客户端尝试用自签名证书访问服务器”:你说的使用自签名的客户端证书,不是吗? Glassfish上的连接器设置是否有特定的配置(特别是信任存储设置)? – Bruno 2012-02-09 12:25:06

+0

“我有一个Java客户端试图访问带有自签名证书的服务器。”:您正在谈论使用自签名的客户端证书,不是吗? - 是的。 – TheCoder 2012-02-09 13:51:25

+0

我在Glassfish JVM中发现了2个设置:-Djavax.net.ssl.keyStore = $ {com.sun.aas.instanceRoot} /config/keystore.jks和-Djavax.net.ssl.trustStore = $ {com.sun .aas.instanceRoot} /config/cacerts.jks。我现在需要通过证书添加其中的一个。你能确认它是我添加到的密钥库吗? – TheCoder 2012-02-09 13:52:50

回答

101

不幸的是 - 这可能是很多事情 - 许多应用程序服务器和其他Java'包装器'都倾向于使用属性来玩,而他们的'自己'则采用钥匙串,而不是。所以它可能会看到完全不同的东西。

短桁架ING的 - 我想尝试:

java -Djavax.net.debug=all -Djavax.net.ssl.trustStore=trustStore ... 

,看看是否有帮助。也可以将其设置为'ssl',密钥管理器和信任管理器,而不是“全部”,这可能有助于解决您的问题。将其设置为'help'将在大多数平台上列出如下所示的内容。

无论 - 确保您完全理解密钥库(您拥有私钥并证明您证明自己的身份)和信任库(它确定您信任的人)之间的区别 - 以及你自己的身份也对根有一个'连锁'的信任 - 这是从任何链条到根,你需要找出'谁'你信任的独立。

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#Debug

+2

非常感谢! -Djavax.net.ssl.trustStore =/location_of/trustStore解决了我的问题,调试信息也非常有帮助。 – RHE 2016-07-19 23:30:27

9

您需要配置JSSE系统属性,特别是指向客户端证书存储区。

通过命令行:

java -Djavax.net.ssl.trustStore=truststores/client.ts com.progress.Client 

或通过Java代码:

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 site

+0

与Spring Boot,Spring Cloud微服务和自签名SSL证书有相同的问题。我能够在application.properties中设置keyStore和keyStorePassword,并使其能够像开箱即用那样工作,但对trustStore和trustStorePassword执行相同的操作并不成功。这个答案适用于我的信任商店。 – 2017-06-30 14:42:21

14

这里是解决方案,遵循步骤以下链接步骤:

http://www.mkyong.com/webservices/jax-ws/suncertpathbuilderexception-unable-to-find-valid-certification-path-to-requested-target/

的Java文件:这是从博客

/* 
* 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 = "abcdef".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); 
    } 
    } 

} 
+2

该解决方案适用于我,但它需要在私有类SavingTrustManager中进行一些小改动:public X509Certificate [] getAcceptedIssuers(){return new X509Certificate [0];} – Richard 2016-07-04 20:29:42

+1

@ Richard,@ Paul,@ user6258309 我得到了错误线程“主”java.net.SocketTimeoutException异常:读取超时 在java.net.SocketInputStream.socketRead0(本地方法) 在java.net.SocketInputStream.socketRead(未知源) 我该如何解决这个问题 – 2017-02-27 05:50:46

-3

缺少的,如果你正在使用类路径变量比方说像pom.xml中的$ {JAVA_HOME}。

<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"/> 

在目标上添加类路径变量。即...,-DANT_HOME,-DJAVA_HOME

clean install -e -DPROJECT_HOME=..... -DANT_HOME=C:\bea1036\modules\org.apache.ant_1.7.1 -DJAVA_HOME=C:\bea1036\jdk160_31 
+0

班级路径和证书无论如何都无关。 – EJP 2017-02-04 07:26:25

+0

我相信你误解了这个问题。 – 2017-06-19 22:29:17

1

我有同样的问题与SBT
它试图通过SSL
来从repo1.maven.org依赖关系,但表示这是“无法找到有效的认证路径要求的目标URL”。
所以我跟着this post 仍然无法验证连接。
所以我读了一下,发现根证书是不够的,正如该职位所建议的 - 所以 -
我工作的东西是将中间CA证书导入密钥库
我实际上在链中添加了所有的证书,它像一个魅力一样工作。

0

我的问题是,通过软件更新,我的工作笔记本电脑上安装了Cloud Access安全代理NetSkope。这正在改变证书链,并且在将整个链导入到我的cacerts密钥库之后,我仍然无法通过我的java客户端连接到服务器。我禁用了NetSkope并能够成功连接。

0

我正在www.udemy.com(REST Java Web Services)上为REST Web服务提供教程。本教程中的示例说,为了拥有SSL,我们必须在我的eclipse“client”项目中有一个名为“trust_store”的文件夹,该文件夹应包含一个“密钥存储”文件(我们有一个“客户”项目来调用服务,以及包含REST Web服务的“服务”项目 - 在同一个eclipse工作区中的两个项目,一个是客户端,另一个是服务)。为了简单起见,他们说从我们正在使用的glassfish应用服务器(glassfish \ domains \ domain1 \ config \ keystore.jsk)复制“keystore.jks”,并将它放到他们让我制作的这个“trust_store”文件夹中客户端项目。这似乎是有道理的:服务器的key_store中的自签名证书将对应于客户端trust_store中的证书。现在,这样做,我得到了原始帖子提到的错误。我已经使用了这个命令,并且发现错误是由于客户端上的“keystore.jks”文件不包含可信/签名证书,它发现的证书是自签名的。

为了保持清楚,让我说,据我了解,“keystore.jsk”包含自签名证书,“cacerts.jks”文件包含CA证书(由CA签名)。 “keystore.jks”是“密钥库”,“cacerts.jks”是“信任库”。正如上面所说的“评论者”Bruno,“keystore.jks”是本地的,“cacerts.jks”是针对远程客户端的。

所以,我对自己说,嘿,glassfish也有“cacerts.jks”文件,它是glassfish的trust_store文件。 cacerts.jsk应该包含CA证书。显然,我需要我的trust_store文件夹来包含至少有一个CA证书的密钥存储文件。所以,我试图把“cacerts”。jks“文件,我在我的客户端项目中创建了”trust_store“文件夹,并将虚拟机属性更改为指向”cacerts.jks“而不是”keystore.jks“,这样就消除了错误。需要有一个CA证书才能工作

这可能不适合生产,甚至是开发之外的工作,例如你可以使用“keytool”命令将CA证书添加到“keystore”中。 JKS”文件中的客户端,但无论如何希望这至少缩小了可能被会在这里造成的错误可能出现的情况

ALSO:。我的方法似乎是为客户有用的(服务器证书添加到客户端trust_store),它看起来像上面解析原始帖子的注释对服务器(客户端证书)很有用添加到服务器的trust_store)。干杯。

Eclipse项目设置:

  • MyClientProject
  • SRC
  • 测试
  • JRE系统库
  • ...
  • trust_store
    --- cacerts.jks - -keystore.jks
从MyClientProject.java文件

段:

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"); 
     } 

    }); 
} 
0

(从my other response转贴)
使用CLI公用密钥工具从Java软件分发进口(和信赖!)需要证书

样品:

  1. 从CLI改变目录到JRE \ BIN

  2. 检查密钥库(JRE中的\ bin目录中找到文件)
    的keytool -list -keystore .. \ lib \ security中\ cacerts中
    密码是的changeit

  3. 从所需的服务器下载并保存链中的所有证书。

  4. 添加证书(之前需要去除 “只读” 的文件 “.. \ lib \ security中\ cacerts的” 属性) 密钥工具-alias REPLACE_TO_ANY_UNIQ_NAME -import -keystore .. \ lib \ security中\的cacerts -file “r:\ root.crt”

不小心我发现了这么简单的提示。 其他解决方案需要使用InstallCert.Java和JDK

来源:http://www.java-samples.com/showtutorial.php?tutorialid=210

相关问题