JavaSSL-InstallCert可以识别证书,但仍然是;找不到有效的证书路径“;错误?

JavaSSL-InstallCert可以识别证书,但仍然是;找不到有效的证书路径“;错误?,ssl,ssl-certificate,java,Ssl,Ssl Certificate,Java,我认为我遇到了和其他人一样的问题,我经历了无数类似的问题和潜在的解决方案,但没有运气 我使用的信任存储是cacerts,位于Java1.6.0JRE(Build1.6.0_20-b02…这可能是问题的根源吗?)的lib/security中。我也试过使用jssecacerts 使用InstallCert(根据发布的其他类似问题),我可以看到我的证书实际上已安装且有效(我已将其删除、重新导入等,以确保看到正确的数据): 不幸的是,我不能允许通过实现我自己的TrustManager来覆盖检查-它必须进

我认为我遇到了和其他人一样的问题,我经历了无数类似的问题和潜在的解决方案,但没有运气

我使用的信任存储是cacerts,位于Java1.6.0JRE(Build1.6.0_20-b02…这可能是问题的根源吗?)的lib/security中。我也试过使用jssecacerts

使用InstallCert(根据发布的其他类似问题),我可以看到我的证书实际上已安装且有效(我已将其删除、重新导入等,以确保看到正确的数据):

不幸的是,我不能允许通过实现我自己的TrustManager来覆盖检查-它必须进行实际检查

我从主机获得的证书有很多扩展(确切地说是9个),这让我怀疑它们是否是这个问题的一部分


我还可以检查/尝试什么?切换到不同的JRE版本?

我猜发生了以下两种情况之一:

a) 您可以在web服务器上运行代码。他们经常使用自己的信任存储—所以您真的确定在执行代码时使用的是
cacerts


b) 默认情况下,Java将通过下载和解释CRL来检查证书的有效性。如果您使用的是代理,下载将失败,因此整个PKIX检查将失败。

SSL调试跟踪将显示您正在使用的cacerts文件,只要您自己不手动加载它。很明显,您没有使用您认为正确的证书。

您仍然可以通过实现自己的信任管理器来检查证书。我遇到了类似的问题。我还尝试将证书添加到
cacerts
,但没有成功

在信任管理器中,需要显式加载证书。基本上我要做的是这样的:

首先,我创建一个使用实际证书文件的信任管理器:

public class ValicertX509TrustManager implements X509TrustManager {

    X509TrustManager pkixTrustManager;

    ValicertX509TrustManager() throws Exception {

        String valicertFile = "/certificates/ValicertRSAPublicRootCAv1.cer";
        String commwebDRFile = "/certificates/DR_10570.migs.mastercard.com.au.crt";
        String commwebPRODFile = "/certificates/PROD_10549.migs.mastercard.com.au.new.crt";

        Certificate valicert = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(valicertFile));
        Certificate commwebDR = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(commwebDRFile));
        Certificate commwebPROD = CertificateFactory.getInstance("X509").generateCertificate(this.getClass().getResourceAsStream(commwebPRODFile));

        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(null, "".toCharArray());
        keyStore.setCertificateEntry("valicert", valicert);
        keyStore.setCertificateEntry("commwebDR", commwebDR);
        keyStore.setCertificateEntry("commwebPROD", commwebPROD);

        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
        trustManagerFactory.init(keyStore);

        TrustManager trustManagers[] = trustManagerFactory.getTrustManagers();

        for(TrustManager trustManager : trustManagers) {
            if(trustManager instanceof X509TrustManager) {
                pkixTrustManager = (X509TrustManager) trustManager;
                return;
            }
        }

        throw new Exception("Couldn't initialize");
    }

    public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        pkixTrustManager.checkServerTrusted(chain, authType);
    }

    public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
        pkixTrustManager.checkServerTrusted(chain, authType);
    }

    public X509Certificate[] getAcceptedIssuers() {
        return pkixTrustManager.getAcceptedIssuers();
    }
}
现在,使用这个信任管理器,我必须创建一个套接字工厂:

public class ValicertSSLProtocolSocketFactory implements ProtocolSocketFactory {

    private SSLContext sslContext = null;

    public ValicertSSLProtocolSocketFactory() {
        super();
    }

    private static SSLContext createValicertSSLContext() {
        try {
            ValicertX509TrustManager valicertX509TrustManager = new ValicertX509TrustManager();
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, new ValicertX509TrustManager[] { valicertX509TrustManager}, null);
            return context;
        }

        catch(Exception e) {
            Log.error(Log.Context.Net, e);
            return null;
        }
    }

    private SSLContext getSSLContext() {
        if(this.sslContext == null) {
            this.sslContext = createValicertSSLContext();
        }

        return this.sslContext;
    }

    public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException {
        return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort);
    }

    public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort, final HttpConnectionParams params) throws IOException {
        if(params == null) {
            throw new IllegalArgumentException("Parameters may not be null");
        }

        int timeout = params.getConnectionTimeout();
        SocketFactory socketFactory = getSSLContext().getSocketFactory();

        if(timeout == 0) {
            return socketFactory.createSocket(host, port, localAddress, localPort);
        }

        else {
            Socket socket = socketFactory.createSocket();
            SocketAddress localAddr = new InetSocketAddress(localAddress, localPort);
            SocketAddress remoteAddr = new InetSocketAddress(host, port);
            socket.bind(localAddr);
            socket.connect(remoteAddr, timeout);
            return socket;
        }
    }

    public Socket createSocket(String host, int port) throws IOException {
        return getSSLContext().getSocketFactory().createSocket(host, port);
    }

    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
        return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    public boolean equals(Object obj) {
        return ((obj != null) && obj.getClass().equals(ValicertSSLProtocolSocketFactory.class));
    }

    public int hashCode() {
        return ValicertSSLProtocolSocketFactory.class.hashCode();
    }
}
然后我刚刚注册了一个新协议:

Protocol.registerProtocol("vhttps", new Protocol("vhttps", new ValicertSSLProtocolSocketFactory(), 443));
PostMethod postMethod = new PostMethod(url);
for (Map.Entry<String, String> entry : params.entrySet()) {
    postMethod.addParameter(entry.getKey(), StringUtils.Nz(entry.getValue()));
}

HttpClient client = new HttpClient();
int status = client.executeMethod(postMethod);
if (status == 200) {
    StringBuilder resultBuffer = new StringBuilder();
    resultBuffer.append(postMethod.getResponseBodyAsString());
    return new HttpResponse(resultBuffer.toString(), "");
} else {
    throw new IOException("Invalid response code: " + status);
}
Protocol.registerProtocol(“vhttps”,新协议(“vhttps”,新ValicertSSLProtocolSocketFactory(),443));
PostMethod PostMethod=新的PostMethod(url);
对于(Map.Entry:params.entrySet()){
postMethod.addParameter(entry.getKey(),StringUtils.Nz(entry.getValue());
}
HttpClient=新的HttpClient();
int status=client.executeMethod(postMethod);
如果(状态==200){
StringBuilder resultBuffer=新StringBuilder();
resultBuffer.append(postMethod.getResponseBodyAsString());
返回新的HttpResponse(resultBuffer.toString(),“”);
}否则{
抛出新IOException(“无效响应代码:+状态”);
}

唯一的缺点是我必须为这个特定证书创建一个特定的协议(
vhttps
)。

因为他直接安装服务器证书,(b)不适用。否则答案很好。@EJP Oops,你是对的,我把它和导入根证书弄混了。一开始我以为A就是它,后来当我把它归结为一个小样本代码,并进行了完整的调试,结果还是失败了,我很沮丧。感谢您的建议。为什么您不能实现自己的
TrustManager
?您仍然可以在信任管理器中使用证书并执行检查。@Vivin-我试图解决的核心问题是在我不直接控制的应用程序层中(在本例中,Grails应用程序调用一些最近仅成为HTTPS的web服务),因此,虽然我可以在我自己的本地场景中使用它,但我不能强制上游使用它。这是一种痛苦,但我会在以后处理它-现在,如果我能使它在最细粒度的水平上工作,它至少告诉我下一步的解决方法。你是在像GlassFish这样的应用服务器下运行的吗?您可以检查进程是否运行/usr/lib/jvm/Java-1.6.0-sun-1.6.0.20.x86_64中的Java二进制文件,而不是不喜欢信任库的其他Java二进制文件(OpenJDK等)。您发布的调试输出很有用,您可以发布更多吗?很难相信所有这些都是真正必要的。有一种明显的味道,就是不理解所有这些潜在的问题。@EJP没有必要如此光顾。我痛苦地意识到这个解决方案不是最优的。如果你有更好的解决办法,我很高兴听到。我尝试了很多方法来实现这一点,包括将证书(我甚至确保可以全程跟踪信任链)添加到服务器的cacerts文件中。似乎什么都没用。在最终使用此解决方案之前,我对这个问题进行了大量研究。这不是我的第一选择。@Vivin-感谢你的建议,尽管我真的希望我不必走这条路。:)我无法直接控制的许多其他代码将不得不更改,因此这是我一直希望自己或机器配置方面出现错误的场景之一。@Bill没问题;很乐意帮忙!我同意,这个问题非常令人沮丧!我希望你能找到一个解决方案。@Vivin我终于找到了一个解决方案-我还没有完全理解它,所以我正在进一步挖掘。当我通过keytool或Portecle在这台特定机器上创建或更新cacerts文件时,我看到了失败,但是当我在另一台机器上创建cacerts并在这台主机上替换我的cacerts文件时,它工作了!那么威德。这似乎表明我在该主机上有一个lib或版本问题,但我仍然不明白为什么来自debugs/etc的所有其他指示都显示为“是的,一切正常!”。一旦我有了一个更确切的理由,我会更新,以防它对其他人有帮助。检查的想法不错,但事实并非如此:“信任库是:/usr/lib/jvm/java-1.6.0-sun-1.6.0.20.x86_64/jre/lib/security/jssecacerts”。正如我提到的,我已经在jssecacerts和cacerts中尝试过,其中包括通过信任库设置强制执行路径。
public class ValicertSSLProtocolSocketFactory implements ProtocolSocketFactory {

    private SSLContext sslContext = null;

    public ValicertSSLProtocolSocketFactory() {
        super();
    }

    private static SSLContext createValicertSSLContext() {
        try {
            ValicertX509TrustManager valicertX509TrustManager = new ValicertX509TrustManager();
            SSLContext context = SSLContext.getInstance("TLS");
            context.init(null, new ValicertX509TrustManager[] { valicertX509TrustManager}, null);
            return context;
        }

        catch(Exception e) {
            Log.error(Log.Context.Net, e);
            return null;
        }
    }

    private SSLContext getSSLContext() {
        if(this.sslContext == null) {
            this.sslContext = createValicertSSLContext();
        }

        return this.sslContext;
    }

    public Socket createSocket(String host, int port, InetAddress clientHost, int clientPort) throws IOException {
        return getSSLContext().getSocketFactory().createSocket(host, port, clientHost, clientPort);
    }

    public Socket createSocket(final String host, final int port, final InetAddress localAddress, final int localPort, final HttpConnectionParams params) throws IOException {
        if(params == null) {
            throw new IllegalArgumentException("Parameters may not be null");
        }

        int timeout = params.getConnectionTimeout();
        SocketFactory socketFactory = getSSLContext().getSocketFactory();

        if(timeout == 0) {
            return socketFactory.createSocket(host, port, localAddress, localPort);
        }

        else {
            Socket socket = socketFactory.createSocket();
            SocketAddress localAddr = new InetSocketAddress(localAddress, localPort);
            SocketAddress remoteAddr = new InetSocketAddress(host, port);
            socket.bind(localAddr);
            socket.connect(remoteAddr, timeout);
            return socket;
        }
    }

    public Socket createSocket(String host, int port) throws IOException {
        return getSSLContext().getSocketFactory().createSocket(host, port);
    }

    public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException {
        return getSSLContext().getSocketFactory().createSocket(socket, host, port, autoClose);
    }

    public boolean equals(Object obj) {
        return ((obj != null) && obj.getClass().equals(ValicertSSLProtocolSocketFactory.class));
    }

    public int hashCode() {
        return ValicertSSLProtocolSocketFactory.class.hashCode();
    }
}
Protocol.registerProtocol("vhttps", new Protocol("vhttps", new ValicertSSLProtocolSocketFactory(), 443));
PostMethod postMethod = new PostMethod(url);
for (Map.Entry<String, String> entry : params.entrySet()) {
    postMethod.addParameter(entry.getKey(), StringUtils.Nz(entry.getValue()));
}

HttpClient client = new HttpClient();
int status = client.executeMethod(postMethod);
if (status == 200) {
    StringBuilder resultBuffer = new StringBuilder();
    resultBuffer.append(postMethod.getResponseBodyAsString());
    return new HttpResponse(resultBuffer.toString(), "");
} else {
    throw new IOException("Invalid response code: " + status);
}