简体   繁体   中英

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated only on production server

Our server suddenly cannot post request to another 3rd service any more through the httpclient and currently there is no one can login to the system. This is our backend code

    public byte[] postContent(final String url, Object... data) {
        Map<String, String> keyValuePairs = SystemUtils.getInstance().buildMap(new HashMap<String, String>(), data);
        final long startTiming = System.currentTimeMillis();
        logger.info("posting, url: " + url);
        HttpClient httpClient = getHttpClient();

        try {
            HttpPost httpPost = new HttpPost(url);
            List <NameValuePair> nvps = new ArrayList <NameValuePair>();
            for (String key : keyValuePairs.keySet()) nvps.add(new BasicNameValuePair(key, keyValuePairs.get(key)));
            httpPost.setEntity(new UrlEncodedFormEntity(nvps));

            ResponseHandler<byte[]> responseHandler = new ResponseHandler<byte[]>() {
                public byte[] handleResponse(final HttpResponse response) throws IOException {
                    int status = response.getStatusLine().getStatusCode();
                    HttpEntity entity = response.getEntity();
                    logger.info("done posting, process: " + (System.currentTimeMillis() - startTiming) + "ms, url: " + url);
                    return entity != null ? EntityUtils.toByteArray(entity) : null;
                }
            };
            return httpClient.execute(httpPost, responseHandler); // cannot execute
        }
        catch (Exception e) {
            throw new SystemException(url + ", " + keyValuePairs.toString(), e);
            }
    }

    private HttpClient getHttpClient() {
        HttpClient base = new  DefaultHttpClient(cm);
        try {
            SSLContext ctx = SSLContext.getInstance("TLS");
            X509TrustManager tm = new X509TrustManager() {

                public void checkClientTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                }

                public void checkServerTrusted(X509Certificate[] xcs, String string) throws CertificateException {
                }

                public X509Certificate[] getAcceptedIssuers() {
                    return null;
                }
            };
            ctx.init(null, new TrustManager[]{tm}, null);
            SSLSocketFactory ssf = new SSLSocketFactory(ctx,SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            ClientConnectionManager ccm = base.getConnectionManager();
            SchemeRegistry sr = ccm.getSchemeRegistry();
            sr.register(new Scheme("https", 443, ssf));
            HttpClient client = new DefaultHttpClient(ccm, base.getParams());
            return client;
        } catch(Exception ex) {
            ex.printStackTrace();
            return base;
        }
    }

And this is the exception

co.abc.xyz.infra.exception.SystemException: https://api.com/verify/json, {....}
    at co.abc.xyz.infra.helper.HttpHelper.postContent(HttpHelper.java:155)
    at co.abc.xyz.infra.helper.NexmoHelper.sendChallenge(NexmoHelper.java:70)
    at co.abc.xyz.infra.controller.SecurityController.mrequestPost(SecurityController.java:89)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at org.springframework.web.method.support.InvocableHandlerMethod.invoke(InvocableHandlerMethod.java:219)
    at
....

Caused by: javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated
    at sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:421)
    at org.apache.http.conn.ssl.AbstractVerifier.verify(AbstractVerifier.java:126)
    at org.apache.http.conn.ssl.SSLSocketFactory.connectSocket(SSLSocketFactory.java:437)
    at org.apache.http.impl.conn.DefaultClientConnectionOperator.openConnection(DefaultClientConnectionOperator.java:180)
    at org.apache.http.impl.conn.AbstractPoolEntry.open(AbstractPoolEntry.java:151)
    at org.apache.http.impl.conn.AbstractPooledConnAdapter.open(AbstractPooledConnAdapter.java:125)
    at org.apache.http.impl.client.DefaultRequestDirector.tryConnect(DefaultRequestDirector.java:643)
    at org.apache.http.impl.client.DefaultRequestDirector.execute(DefaultRequestDirector.java:479)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:906)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:1138)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:1076)
    at org.apache.http.impl.client.AbstractHttpClient.execute(AbstractHttpClient.java:1050)
    at co.abc.xyz.infra.helper.HttpHelper.postContent(HttpHelper.java:152)
    ... 75 more

On my local, everything is working fine and this only happens on the production server. Is there anyone having any clue for this?

You do not have any certificate and truststore ? Maybe it is because of the absence of truststore... I suggest you to check if root certificates and certificate chains are the same (and valids) on every system environments.

If you are using Spring/Apache HTTP Client, you can also init your SSLContext like this (depends on Keystore/Trustore types) :

final KeyStore keyStore = KeyStore.getInstance("PKCS12");
keyStore.load(keyStoreFile.getInputStream(), keyStorePassword.toCharArray());

final KeyStore trustStore = KeyStore.getInstance("JCEKS");
trustStore.load(trustStoreFile.getInputStream(), trustStorePassword.toCharArray());

SSLContext sslContext = new SSLContextBuilder()
                                .loadTrustMaterial(
                                    trustStore, 
                                    new TrustStrategy(){
                                        @Override
                                        public boolean isTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                                            return true;
                                        }
                                    })
                                .loadKeyMaterial(
                                    keyStore, 
                                    keyStorePassword.toCharArray())
                                .build();

Also, you can add -Djavax.net.debug=ssl to turn on SSL debugging on the JVM.

I sent the email to the 3rd service to ask about the problem and got the reply that they just updated to TLSv1.2, thus by default Java 1.7 use TLSv1.1 and it gave this exception.

I only need to change the line

SSLContext ctx = SSLContext.getInstance("TLS");

to

SSLContext ctx = SSLContext.getInstance("TLSv1.2");

And server is back to normal again. This is such a tragedy.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM