代码之家  ›  专栏  ›  技术社区  ›  Jan

HTTPS/SSL上的Java客户端证书

  •  124
  • Jan  · 技术社区  · 17 年前

    HttpsURLConnection
    /System/Library/Frameworks/JavaVM.framework/Versions/1.6.0/Home/lib/security/cacerts

    javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed' problem.


    首先,也是首选,尝试:

    SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
    URL url = new URL("https://somehost.dk:3049");
    HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
    conn.setSSLSocketFactory(sslsocketfactory);
    InputStream inputstream = conn.getInputStream();
    // The last line fails, and gives:
    // javax.net.ssl.SSLHandshakeException: Received fatal alert: handshake_failure
    

    我尝试跳过HttpsURLConnection类(这并不理想,因为我想与服务器进行HTTP通信),而是这样做:

    SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
    SSLSocket sslsocket = (SSLSocket) sslsocketfactory.createSocket("somehost.dk", 3049);
    InputStream inputstream = sslsocket.getInputStream();
    // do anything with the inputstream results in:
    // java.net.SocketTimeoutException: Read timed out
    

    我甚至不确定客户端证书是否是这里的问题。

    9 回复  |  直到 15 年前
        1
  •  104
  •   javanna Jayendra    15 年前

    终于解决了;).得到了一个强烈的暗示 here (Gandals的回答也稍微触及了这一点)。缺少的链接(主要)是下面的第一个参数,在某种程度上,我忽略了密钥库和信任库之间的区别。

    keytool-import-别名gridserver-文件gridserver.crt-storepass$PASS-密钥库gridserver.keystore

    -Djavax.net.ssl.keyStoreType=pkcs12
    -Djavax.net.ssl.trustStoreType=jks
    -Djavax.net.ssl.keyStore=clientcertificate.p12
    -Djavax.net.ssl.trustStore=gridserver.keystore
    -Djavax.net.debug=ssl # very verbose debug
    -Djavax.net.ssl.keyStorePassword=$PASS
    -Djavax.net.ssl.trustStorePassword=$PASS
    

    工作示例代码:

    SSLSocketFactory sslsocketfactory = (SSLSocketFactory) SSLSocketFactory.getDefault();
    URL url = new URL("https://gridserver:3049/cgi-bin/ls.py");
    HttpsURLConnection conn = (HttpsURLConnection)url.openConnection();
    conn.setSSLSocketFactory(sslsocketfactory);
    InputStream inputstream = conn.getInputStream();
    InputStreamReader inputstreamreader = new InputStreamReader(inputstream);
    BufferedReader bufferedreader = new BufferedReader(inputstreamreader);
    
    String string = null;
    while ((string = bufferedreader.readLine()) != null) {
        System.out.println("Received " + string);
    }
    
        2
  •  84
  •   neu242    11 年前

    The Java Developers Almanac :

    import javax.net.ssl.*; import java.security.SecureRandom; import
    java.security.cert.X509Certificate;
    
    public class SSLTool {
    
      public static void disableCertificateValidation() {
        // Create a trust manager that does not validate certificate chains
        TrustManager[] trustAllCerts = new TrustManager[] { 
          new X509TrustManager() {
            public X509Certificate[] getAcceptedIssuers() { 
              return new X509Certificate[0]; 
            }
            public void checkClientTrusted(X509Certificate[] certs, String authType) {}
            public void checkServerTrusted(X509Certificate[] certs, String authType) {}
        }};
    
        // Ignore differences between given hostname and certificate hostname
        HostnameVerifier hv = new HostnameVerifier() {
          public boolean verify(String hostname, SSLSession session) { return true; }
        };
    
        // Install the all-trusting trust manager
        try {
          SSLContext sc = SSLContext.getInstance("SSL");
          sc.init(null, trustAllCerts, new SecureRandom());
          HttpsURLConnection.setDefaultSSLSocketFactory(sc.getSocketFactory());
          HttpsURLConnection.setDefaultHostnameVerifier(hv);
        } catch (Exception e) {}   } }
    
        3
  •  21
  •   Gandalf    17 年前

    您是否设置了KeyStore和/或TrustStore系统属性?

    java -Djavax.net.ssl.keyStore=pathToKeystore -Djavax.net.ssl.keyStorePassword=123456
    

    或使用代码

    System.setProperty("javax.net.ssl.keyStore", pathToKeyStore);
    

        4
  •  13
  •   Mark Meuer    16 年前

    如果您使用Axis框架处理web服务调用,则有一个更简单的答案。如果只希望您的客户端能够调用SSL web服务并忽略SSL证书错误,只需在调用任何web服务之前放置以下语句:

    System.setProperty("axis.socketSecureFactory", "org.apache.axis.components.net.SunFakeTrustSocketFactory");

    我在以下位置找到了这个 the Axis wiki .

        5
  •  6
  •   EpicPandaForce Jigar Joshi    11 年前

    对我来说,这就是使用Apache HttpComponents ~HttpClient 4.x时的工作原理:

        KeyStore keyStore  = KeyStore.getInstance("PKCS12");
        FileInputStream instream = new FileInputStream(new File("client-p12-keystore.p12"));
        try {
            keyStore.load(instream, "helloworld".toCharArray());
        } finally {
            instream.close();
        }
    
        // Trust own CA and all self-signed certs
        SSLContext sslcontext = SSLContexts.custom()
            .loadKeyMaterial(keyStore, "helloworld".toCharArray())
            //.loadTrustMaterial(trustStore, new TrustSelfSignedStrategy()) //custom trust store
            .build();
        // Allow TLSv1 protocol only
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
            sslcontext,
            new String[] { "TLSv1" },
            null,
            SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER); //TODO
        CloseableHttpClient httpclient = HttpClients.custom()
            .setHostnameVerifier(SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER) //TODO
            .setSSLSocketFactory(sslsf)
            .build();
        try {
    
            HttpGet httpget = new HttpGet("https://localhost:8443/secure/index");
    
            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());
                if (entity != null) {
                    System.out.println("Response content length: " + entity.getContentLength());
                }
                EntityUtils.consume(entity);
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
    

    public static byte[] convertPEMToPKCS12(final String keyFile, final String cerFile,
        final String password)
        throws IOException, CertificateException, KeyStoreException, NoSuchAlgorithmException,
        NoSuchProviderException
    {
        // Get the private key
        FileReader reader = new FileReader(keyFile);
    
        PEMParser pem = new PEMParser(reader);
        PEMKeyPair pemKeyPair = ((PEMKeyPair)pem.readObject());
        JcaPEMKeyConverter jcaPEMKeyConverter = new JcaPEMKeyConverter().setProvider("BC");
        KeyPair keyPair = jcaPEMKeyConverter.getKeyPair(pemKeyPair);
    
        PrivateKey key = keyPair.getPrivate();
    
        pem.close();
        reader.close();
    
        // Get the certificate
        reader = new FileReader(cerFile);
        pem = new PEMParser(reader);
    
        X509CertificateHolder certHolder = (X509CertificateHolder) pem.readObject();
        java.security.cert.Certificate x509Certificate =
            new JcaX509CertificateConverter().setProvider("BC")
                .getCertificate(certHolder);
    
        pem.close();
        reader.close();
    
        // Put them into a PKCS12 keystore and write it to a byte[]
        ByteArrayOutputStream bos = new ByteArrayOutputStream();
        KeyStore ks = KeyStore.getInstance("PKCS12", "BC");
        ks.load(null);
        ks.setKeyEntry("key-alias", (Key) key, password.toCharArray(),
            new java.security.cert.Certificate[]{x509Certificate});
        ks.store(bos, password.toCharArray());
        bos.close();
        return bos.toByteArray();
    }
    
        7
  •  4
  •   sourcerebels    17 年前

    keytool :

    keytool
        -import
        -alias <provide_an_alias>
        -file <certificate_file>
        -keystore <your_path_to_jre>/lib/security/cacerts
    
        8
  •  1
  •   Amr Kamel Ankur Singhal    12 年前

    使用以下代码

    -Djavax.net.ssl.keyStoreType=pkcs12
    

    System.setProperty("javax.net.ssl.keyStore", pathToKeyStore);
    

    根本不需要。也不需要创建自己的自定义SSL工厂。

    我也遇到了同样的问题,就我而言,有一个问题

    此外,应在运行应用程序的服务器中配置cacerts文件,这两台服务器将使用公钥/私钥进行相互身份验证。

    推荐文章