Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ssl/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java证书客户端SSL:找不到请求目标的有效证书路径_Java_Ssl_Certificate_Client_Pem - Fatal编程技术网

Java证书客户端SSL:找不到请求目标的有效证书路径

Java证书客户端SSL:找不到请求目标的有效证书路径,java,ssl,certificate,client,pem,Java,Ssl,Certificate,Client,Pem,我们需要客户端身份验证来向一些web服务发送RESTful请求。我已经通过密钥工具在本地mac os上安装了客户端证书(.pem)和密钥。这些不是自签名的 openssl pkcs12 -export -name myservercert -in not_self_signed.crt -inkey server.key -out keystore.p12 …并转换为JKS格式 keytool -importkeystore -destkeystore mykeystore.jks -srck

我们需要客户端身份验证来向一些web服务发送RESTful请求。我已经通过密钥工具在本地mac os上安装了客户端证书(.pem)和密钥。这些不是自签名的

openssl pkcs12 -export -name myservercert -in not_self_signed.crt -inkey server.key -out keystore.p12
…并转换为JKS格式

keytool -importkeystore -destkeystore mykeystore.jks -srckeystore keystore.p12 -srcstoretype pkcs12 -alias myservercert
我正在尝试构建一个Java客户端来进行身份验证。以下是我到目前为止得出的结论:

import java.io.FileInputStream;
import java.security.KeyStore;

import javax.net.ssl.SSLContext;

import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;


public class TestClientCustomSSL {

    public final static void main(String[] args) throws Exception {

        KeyStore keyStore = KeyStore.getInstance("JKS");
        keyStore.load(new FileInputStream("/Users/me/mykeystore.jks"), "mypassword".toCharArray());

        SSLContext sslContext = SSLContexts.custom().loadKeyMaterial(keyStore, "mypassword".toCharArray()).build();

        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslContext,
                new String[] {"TLSv1"},
                null,
                SSLConnectionSocketFactory.getDefaultHostnameVerifier());

        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();

        try {

            HttpGet httpget = new HttpGet("https://restful-service-i-am-calling/v1/endpoint/data?ip=0.0.0.1");

            System.out.println("Executing request " + httpget.getRequestLine());

            CloseableHttpResponse response = httpclient.execute(httpget);
            try {
                HttpEntity entity = response.getEntity();

                System.out.println("----------------------------------------");
                System.out.println(response.getStatusLine());
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    }

}
下面是我收到的stacktrace。但是根据我读到的内容,我的班级应该能够发送请求

Exception in thread "main" 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
    at sun.security.ssl.Alerts.getSSLException(Alerts.java:192)
    at sun.security.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1884)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:276)
    at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:270)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1439)
    at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:209)
    at sun.security.ssl.Handshaker.processLoop(Handshaker.java:878)
    at sun.security.ssl.Handshaker.process_record(Handshaker.java:814)
    at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1016)
    at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1312)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1339)
    at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1323)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.createLayeredSocket(SSLConnectionSocketFactory.java:394)
    at org.apache.http.conn.ssl.SSLConnectionSocketFactory.connectSocket(SSLConnectionSocketFactory.java:353)
    at org.apache.http.impl.conn.DefaultHttpClientConnectionOperator.connect(DefaultHttpClientConnectionOperator.java:134)
    at org.apache.http.impl.conn.PoolingHttpClientConnectionManager.connect(PoolingHttpClientConnectionManager.java:353)
    at org.apache.http.impl.execchain.MainClientExec.establishRoute(MainClientExec.java:380)
    at org.apache.http.impl.execchain.MainClientExec.execute(MainClientExec.java:236)
    at org.apache.http.impl.execchain.ProtocolExec.execute(ProtocolExec.java:184)
    at org.apache.http.impl.execchain.RetryExec.execute(RetryExec.java:88)
    at org.apache.http.impl.execchain.RedirectExec.execute(RedirectExec.java:110)
    at org.apache.http.impl.client.InternalHttpClient.doExecute(InternalHttpClient.java:184)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:82)
    at org.apache.http.impl.client.CloseableHttpClient.execute(CloseableHttpClient.java:107)
    at com.mycompany.main(ClientCustomSSL.java:101)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:385)
    at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:292)
    at sun.security.validator.Validator.validate(Validator.java:260)
    at sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:326)
    at sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:231)
    at sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:126)
    at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1421)
    ... 20 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
    at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:196)
    at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:268)
    at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:380)
    ... 26 more
任何指点都很感激

编辑::

仅供参考,我能够使用与我使用wget添加到信任存储的相同的pem和密钥从服务器获得200响应

wget --certificate ~/Desktop/my.cert.pem --private-key ~/Desktop/my.key.key https://mycompany.com/v1/939044?data=0.0.0.1
编辑2::*

根据下面的@EJP应答,还从服务器站点添加了证书:

openssl x509 -in <(openssl s_client -connect the.api.i.am.calling.com:443 -prexit 2>/dev/null) -out ~/Desktop/the.api.i.am.calling.crt
运行list命令显示两个证书都在密钥库中:

keytool -importcert -file ~/Desktop/the.api.i.am.calling.crt -alias the.api.i.am.calling.com -keystore /Users/me/mykeystore.jks -storepass mypassword
keytool -list -keystore /Users/me/mykeystore.jks 
Enter keystore password:  *********

Keystore type: JKS
Keystore provider: SUN

Your keystore contains 2 entries

my.auth.client.cert.com, Oct 17, 2015, PrivateKeyEntry, 
Certificate fingerprint (SHA1): 3D:95:32:E5:F9:9E:4A:53:84:EB:AB:1B:B9:A2:4C:A5:1B:5E:DA:76
the.api.i.am.calling.com, Oct 18, 2015, trustedCertEntry, 
Certificate fingerprint (SHA1): 7C:4A:7B:CE:9B:0B:92:C0:4F:C0:DA:84:CF:F2:24:CF:99:83:0B:3F
但我仍然收到同样的错误

编辑3::


还有一件事我忘了提。我给服务器端团队的唯一东西就是我们的客户端证书名。。。比如dev.auth.client.com。我真的必须将服务器端证书存储在密钥库中吗?

它与您的客户端证书无关。您的信任库不信任服务器证书

  • 使用openssl生成P12文件

    openssl pkcs12-export-in/Users/me/test.authclient.int.com.crt-inkey/Users/me/test.authclient.int.com.key-out-authclient.p12-name-authClientCert

  • 生成信任存储密钥

    keytool-genkey-dname“cn=CLIENT”-别名trustStoreKey-keyalg RSA-keystore authClient-truststore.jks-keypass mypassword-storepass mypassword

  • 现在,导入信任存储密钥

    keytool-import-keystore-authClient-truststore.jks-file/Users/me/test.authClient.int.com/test.authClient.int.com.crt-alias.test.authClient.int.com

  • 获取远程证书

    openssl x509-in/dev/null)-out.api.i.want.to.call.crt

  • 将服务器证书添加到信任存储

    keytool-importcert-file the.api.i.want.to.call.crt-别名the.api.i.want.to.call.com-keystore/Users/me/authClient-truststore.jks-storepass mypassword

  • 这是我用来调用需要身份验证的api的客户端

        KeyStore clientStore = KeyStore.getInstance("PKCS12");
        clientStore.load(new FileInputStream("/Users/me/authClient.p12"), "mypassword".toCharArray());
    
        KeyManagerFactory kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
        kmf.init(clientStore, "mypassword".toCharArray());
        KeyManager[] keyManagers = kmf.getKeyManagers();
    
        KeyStore trustStore = KeyStore.getInstance("JKS");
        trustStore.load(new FileInputStream("/Users/me/authClient-truststore.jks"), "mypassword".toCharArray());
    
        TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
        tmf.init(trustStore);
        TrustManager[] tms = tmf.getTrustManagers();
    
        SSLContext sslContext = SSLContext.getInstance("TLS");
        sslContext.init(keyManagers, tms, new SecureRandom());
    
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
        CloseableHttpClient httpclient = HttpClients.custom().setSSLSocketFactory(sslsf).build();
    
        HttpGet httpget = new HttpGet(requestUrl);
    
        httpclient.execute(httpget);
    

    不是这样。让我知道我是否可以通过扩展来帮助您,但这应该是您所需要的全部。

    谢谢EJP。如果您不介意提供一些关于如何使其信任服务器证书的详细信息,这将非常有用。我在本地运行这个。真正的问题是为什么服务器证书没有签名?如果它们都是您的证书,请从服务器密钥库导出服务器证书,并使用keytool将其作为受信任证书导入到您的客户端信任库中。如果是这种情况,我是否能够发送此证书?从我当地的经验来看,效果很好。wget--certificate~/Desktop/my.cert.pem--private key~/Desktop/my.key.key我已将服务器证书添加到密钥库中。编辑2显示此更新。。。还是一样的结果。任何额外的建议我都很感激。我无法理解这一点。步骤1不使用keytool。步骤2生成一个密钥对,该密钥对位于密钥库中。步骤3导入证书,而不是密钥。客户机密钥库和信任库都混在一起了。步骤4-5正是你所说的不起作用的。我相信其他人会发现这一点useful@MattB,谢谢你的解决方案。这是唯一适用于authClient身份验证的方法。