39

Using HttpClient, I receive the following error when attempting to communicate over HTTPS:

Exception in thread "main" javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated.

Here is my code:

URI loginUri = new URI("https://myUrl.asp");

HttpClient httpclient = new DefaultHttpClient();
HttpGet httpget = new HttpGet( loginUri );
HttpResponse response = httpclient.execute( httpget );

How do I suppress or remove this error?

CSchulz
  • 10,882
  • 11
  • 60
  • 114
Stefan Kendall
  • 66,414
  • 68
  • 253
  • 406
  • 1
    JDK version? HttpClient version? Also, if you could provide the full stack trace and the URL (is it a public website or not, are you using a self-signed certificate or not), it might help. – Pascal Thivent Feb 22 '10 at 07:30
  • It's a self signed cert. I linked to the version of HttpClient I'm using (4.x, whatever's stable), and I'm using Java 6. I need to ignore this error and perform the get REGARDLESS of the site I'm connecting to. – Stefan Kendall Feb 22 '10 at 14:48
  • 1
    Readers might be interested in this related question: [Self Signed SSL acceptance Android](http://stackoverflow.com/questions/1217141/self-signed-ssl-acceptance-android) – Mat Mar 09 '13 at 15:50
  • Note that it would be best to create a specific `KeyStore` or a `TrustManager` to connect to a specific server that is not verified by one of the pre-installed root certificates, or to create self signed certificates and use those. If you just skip over the problem, then your SSL connection is not secure anymore. – Maarten Bodewes Oct 16 '14 at 21:28

6 Answers6

17

Note: Do not do this in production code, use http instead, or the actual self signed public key as suggested above.

On HttpClient 4.xx:

import static org.junit.Assert.assertEquals;

import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;

import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.junit.Test;

public class HttpClientTrustingAllCertsTest {

    @Test
    public void shouldAcceptUnsafeCerts() throws Exception {
        DefaultHttpClient httpclient = httpClientTrustingAllSSLCerts();
        HttpGet httpGet = new HttpGet("https://host_with_self_signed_cert");
        HttpResponse response = httpclient.execute( httpGet );
        assertEquals("HTTP/1.1 200 OK", response.getStatusLine().toString());
    }

    private DefaultHttpClient httpClientTrustingAllSSLCerts() throws NoSuchAlgorithmException, KeyManagementException {
        DefaultHttpClient httpclient = new DefaultHttpClient();

        SSLContext sc = SSLContext.getInstance("SSL");
        sc.init(null, getTrustingManager(), new java.security.SecureRandom());

        SSLSocketFactory socketFactory = new SSLSocketFactory(sc);
        Scheme sch = new Scheme("https", 443, socketFactory);
        httpclient.getConnectionManager().getSchemeRegistry().register(sch);
        return httpclient;
    }

    private TrustManager[] getTrustingManager() {
        TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
            @Override
            public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                return null;
            }

            @Override
            public void checkClientTrusted(X509Certificate[] certs, String authType) {
                // Do nothing
            }

            @Override
            public void checkServerTrusted(X509Certificate[] certs, String authType) {
                // Do nothing
            }

        } };
        return trustAllCerts;
    }
}
Jonas Andersson
  • 8,678
  • 2
  • 19
  • 14
  • 5
    And again, for anybody that is interested in security, this does not fix the underlying problem. Import the certificate in your certificate store, but don't trust all connections as you might as well not use SSL. – Maarten Bodewes Oct 04 '12 at 23:56
  • 8
    Of course. Doing the above in production code would be incredibly counter productive. But if you don't care about security, for example in an end-to-end test against a development server, it's nice to not depend on the server certs. – Jonas Andersson Oct 05 '12 at 11:27
  • Thanks for the edit, it never hurts to make that kind of security warning explicit. – Maarten Bodewes Oct 05 '12 at 23:13
  • @owlstead "you might as well not use SSL" I use SSL only for encryption, not for authenticating the server to the client, how is this not safe? – dalvarezmartinez1 Nov 22 '13 at 12:38
  • 3
    I assume your purpose for using encryption is preventing man-in-the-middle to read your data. If so, without authenticating the cert, you don't know who is at the other end, it could be the man-in-the-middle proxying the communication, i.e. decrypting it, reading it, encrypting it, passing it on. You'll never know... – Jonas Andersson Nov 24 '13 at 19:33
17

This answer follows on to owlstead and Mat's responses. It applies to SE/EE installations, not ME/mobile/Android SSL.

Since no one has yet mentioned it, I'll mention the "production way" to fix this: Follow the steps from the AuthSSLProtocolSocketFactory class in HttpClient to update your trust store & key stores.

  1. Import a trusted certificate and generate a truststore file

keytool -import -alias "my server cert" -file server.crt -keystore my.truststore

  1. Generate a new key (use the same password as the truststore)

keytool -genkey -v -alias "my client key" -validity 365 -keystore my.keystore

  1. Issue a certificate signing request (CSR)

keytool -certreq -alias "my client key" -file mycertreq.csr -keystore my.keystore

  1. (self-sign or get your cert signed)

  2. Import the trusted CA root certificate

keytool -import -alias "my trusted ca" -file caroot.crt -keystore my.keystore

  1. Import the PKCS#7 file containg the complete certificate chain

keytool -import -alias "my client key" -file mycert.p7 -keystore my.keystore

  1. Verify the resultant keystore file's contents

keytool -list -v -keystore my.keystore

If you don't have a server certificate, generate one in JKS format, then export it as a CRT file. Source: keytool documentation

keytool -genkey -alias server-alias -keyalg RSA -keypass changeit
    -storepass changeit -keystore my.keystore

keytool -export -alias server-alias -storepass changeit
    -file server.crt -keystore my.keystore
Community
  • 1
  • 1
Barett
  • 5,826
  • 6
  • 51
  • 55
12

Using HttpClient 3.x, you need to do this:

Protocol easyHttps = new Protocol("https", new EasySSLProtocolSocketFactory(), 443);
Protocol.registerProtocol("https", easyHttps);

An implementation of EasySSLProtocolSocketFactory can be found here.

Tom
  • 4,742
  • 25
  • 32
Stefan Kendall
  • 66,414
  • 68
  • 253
  • 406
  • Updated URL. All you really need to do is google `EasySSLProtocolSocketFactory`. The exact string is so specific that it seemed like there were no bad results. – Stefan Kendall May 16 '11 at 13:47
  • 23
    It should be noted that this method does exactly what the question asks for: it supresses the error message. It doesn't actually solve the problem since the connection is insecure. The right way would be to import the remote certificate explictly in your trust store. – Bruno Mar 21 '12 at 23:00
  • 1
    This doesn't fix the problem, and the link leads to a parked page :/ – Steven Schlansker May 15 '18 at 23:34
4

This exception will come in case your server is based on JDK 7 and your client is on JDK 6 and using SSL certificates. In JDK 7 sslv2hello message handshaking is disabled by default while in JDK 6 sslv2hello message handshaking is enabled. For this reason when your client trying to connect server then a sslv2hello message will be sent towards server and due to sslv2hello message disable you will get this exception. To solve this either you have to move your client to JDK 7 or you have to use 6u91 version of JDK. But to get this version of JDK you have to get the

Tanuj Kumar
  • 191
  • 1
  • 3
0

Method returning a "secureClient" (in a Java 7 environnement - NetBeans IDE and GlassFish Server: port https by default 3920 ), hope this could help :

public DefaultHttpClient secureClient() {
    DefaultHttpClient httpclient = new DefaultHttpClient();
    SSLSocketFactory sf;

    KeyStore trustStore;
    FileInputStream trustStream = null;
    File truststoreFile;
    // java.security.cert.PKIXParameters for the trustStore
    PKIXParameters pkixParamsTrust;

    KeyStore keyStore;
    FileInputStream keyStream = null;
    File keystoreFile;
    // java.security.cert.PKIXParameters for the keyStore
    PKIXParameters pkixParamsKey;

    try {
        trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
        truststoreFile = new File(TRUSTSTORE_FILE);
        keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keystoreFile = new File(KEYSTORE_FILE);
        try {
            trustStream = new FileInputStream(truststoreFile);
            keyStream = new FileInputStream(keystoreFile);
        } catch (FileNotFoundException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            trustStore.load(trustStream, PASSWORD.toCharArray());
            keyStore.load(keyStream, PASSWORD.toCharArray());
        } catch (IOException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (CertificateException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            pkixParamsTrust = new PKIXParameters(trustStore);
            // accepts Server certificate generated with keytool and (auto) signed by SUN
            pkixParamsTrust.setPolicyQualifiersRejected(false);
        } catch (InvalidAlgorithmParameterException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            pkixParamsKey = new PKIXParameters(keyStore);
            // accepts Client certificate generated with keytool and (auto) signed by SUN
            pkixParamsKey.setPolicyQualifiersRejected(false);
        } catch (InvalidAlgorithmParameterException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        }
        try {
            sf = new SSLSocketFactory(trustStore);
            ClientConnectionManager manager = httpclient.getConnectionManager();
            manager.getSchemeRegistry().register(new Scheme("https", 3920, sf));
        } catch (KeyManagementException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        } catch (UnrecoverableKeyException ex) {
            Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
        }

    } catch (NoSuchAlgorithmException ex) {
        Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
    } catch (KeyStoreException ex) {
        Logger.getLogger(ApacheHttpRestClient.class.getName()).log(Level.SEVERE, null, ex);
    }
    // use the httpclient for any httpRequest
    return httpclient;
}
0

Your local JVM or remote server may not have the required ciphers. go here

https://www.oracle.com/java/technologies/javase-jce8-downloads.html

and download the zip file that contains: US_export_policy.jar and local_policy.jar

replace the existing files (you need to find the existing path in your JVM).

on a Mac, my path was here. /Library/Java/JavaVirtualMachines/jdk1.8.0_131.jdk/Contents/Home/jre/lib/security

this worked for me.

rob345
  • 203
  • 2
  • 11