Remember a certificate issue request failed because of a problem SSLHandshakeException

Remember a certificate issue request failed because of a problem SSLHandshakeException

Please indicate the source: https://www.cnblogs.com/funnyzpc/p/10989813.html

Recently received an external interface, the interface in local development and debugging tests without any problem (windows down), and after the test environment directly measured for the first time reported the error,
the error is like this:

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:1917)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:301)
        at sun.security.ssl.Handshaker.fatalSE(Handshaker.java:295)
        at sun.security.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1369)
        at sun.security.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:156)
        at sun.security.ssl.Handshaker.processLoop(Handshaker.java:925)
        at sun.security.ssl.Handshaker.process_record(Handshaker.java:860)
        at sun.security.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:1043)
        at sun.security.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1343)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1371)
        at sun.security.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1355)

enn ~, the first interface address is https, the server is the linux; more errors to the effect that can not be found and validated certificate, think again: No, ah, jdk jdk local and server are official oracle jdk 1.8 Yeah, it is reasonable He said
local commissioning is no problem on the server should not be a problem it ~

~ Eh, no matter how the analysis will still have to solve the problem that way, let me analyze this in turn two problems:

  • Local and server OS inconsistent
  • Incompatibility issues SSL certificates or other interface address

How to do? Ask for inspection certificate configuration, is unlikely, the rest is only one way: to be compatible with each other is trust certificates at the time of the request.

So with the first edition.

Because I'm using CloseableHttpClient, made the request management, better to let CloseableHttpClient compatible with https and not http like, wondering item, something the code search Serve
(here only gives the core code)

    // 之前
    // private static CloseableHttpClient httpClient = HttpClients.custom().build();

    // 之后
    private static CloseableHttpClient httpClient;
    static {
        try {
            System.out.println("===>01");
            // 忽略证书
            SSLContextBuilder SslBuilder = new SSLContextBuilder().loadTrustMaterial(null, new TrustSelfSignedStrategy());
            //不进行主机名验证
            SSLConnectionSocketFactory sslConnectionSocketFactory = new SSLConnectionSocketFactory(SslBuilder.build(), NoopHostnameVerifier.INSTANCE);
            Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
                    .register("http", new PlainConnectionSocketFactory())
                    .register("https", sslConnectionSocketFactory)
                    .build();
            PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
            cm.setMaxTotal(100);
            httpClient = HttpClients.custom()
                    .setSSLSocketFactory(sslConnectionSocketFactory)
                    .setDefaultCookieStore(new BasicCookieStore())
                    .setConnectionManager(cm).build();
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("===>02");
            httpClient = HttpClients.custom().build();
        }
    }

bingo ~, on-line measurement. . .

oh ~, no, this is still wrong:

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)
        ......

I analyzed a lot to be found just to the above code does not verify the other host, completely ignored the wrong certificate. . . - Hey, this is a problem.

I thought before the company also has appeared on this issue, ha ~, there are ways to find the source of the main copy over a few walk is not enough.

So, Second Edition

Core code:


HostnameVerifier hv = new HostnameVerifier() {
        public boolean verify(String urlHostName, SSLSession session) {
            return true;
        }
    };

 private static void trustAllHttpsCertificates() throws Exception {
     javax.net.ssl.TrustManager[] trustAllCerts = new javax.net.ssl.TrustManager[1];
     javax.net.ssl.TrustManager tm = new miTM();
     trustAllCerts[0] = tm;
     javax.net.ssl.SSLContext sc = javax.net.ssl.SSLContext
     .getInstance("SSL");
     sc.init(null, trustAllCerts, null);
     javax.net.ssl.HttpsURLConnection.setDefaultSSLSocketFactory(sc
     .getSocketFactory());
 }

 static class miTM implements javax.net.ssl.TrustManager,
 javax.net.ssl.X509TrustManager {
     public java.security.cert.X509Certificate[] getAcceptedIssuers() {
     return null;
 }

 public boolean isServerTrusted(
     java.security.cert.X509Certificate[] certs) {
     return true;
 }

 public boolean isClientTrusted(
     java.security.cert.X509Certificate[] certs) {
     return true;
 }

 public void checkServerTrusted(
     java.security.cert.X509Certificate[] certs, String authType)
     throws java.security.cert.CertificateException {
     return;
 }

 public void checkClientTrusted(
     java.security.cert.X509Certificate[] certs, String authType)
     throws java.security.cert.CertificateException {
        return;
     }
 }

 // 在访问前调用
 trustAllHttpsCertificates();
 HttpsURLConnection.setDefaultHostnameVerifier(hv);

Toss a full deployment test on the line, ah ~, or the same error. . .

Analysis of the code, see, this processing logic is only valid for a custom SSL certificate for my current situation can not have the slightest problem solved

Final version

In fact, what business did not change the code, just add a little something to jdk.
The main idea is to solve jdk ignores the specified domain SSL certificate.

//InstallCert.java


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

Specific solutions steps:

  • Compile file
    • javac InstallCert.java
  • Add trust
    • java InstallCert 域名地址
  • Upload certificate (site certificate will need to manually export)
    • rz => 证书.cer
  • Import Certificate (password: changeit)
    • echo $JAVA_HOME
    • keytool -import -alias LL1 -keystore $JAVA_HOME/jre/lib/security/cacerts -file /home/证书.cer

Guess you like

Origin www.cnblogs.com/funnyzpc/p/10989813.html