Httpget with Https:Sslpeerunverifiedexception

HttpGet with HTTPS : SSLPeerUnverifiedException

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.

HttpClient javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated when time shifted?

It is possible to make HttpClient get around the checks of SSL certificate validity. This code can be used to obtain an instance of HttpClient:

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.security.SecureRandom;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
......
private static HttpClient getHttpClient() {

try {
SSLContext sslContext = SSLContext.getInstance("SSL");

sslContext.init(null,
new TrustManager[]{new X509TrustManager() {
public X509Certificate[] getAcceptedIssuers() {

return null;
}

public void checkClientTrusted(
X509Certificate[] certs, String authType) {

}

public void checkServerTrusted(
X509Certificate[] certs, String authType) {

}
}}, new SecureRandom());

SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext,SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);

HttpClient httpClient = HttpClientBuilder.create().setSSLSocketFactory(socketFactory).build();

return httpClient;

} catch (Exception e) {
e.printStackTrace();
return HttpClientBuilder.create().build();
}
}

The exception will no longer be thrown, when the certification is expired, the browser will issues a warning about an expired certificate and let user confirm.

Apache HTTPClient SSLPeerUnverifiedException

EDIT I realise this answer was accepted a long time ago and has also been upvoted 3 times, but it was (at least partly) incorrect, so here is a bit more about this exception. Apologies for the inconvenience.

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

This is usually an exception thrown when the remote server didn't send a certificate at all. However, there is an edge case, which is encountered when using Apache HTTP Client, because of the way it was implemented in this version, and because of the way sun.security. ssl.SSLSocketImpl.getSession() is implemented.

When using Apache HTTP Client, this exception will also be thrown when the remote certificate isn't trusted, which would more often throw "sun.security.validator.ValidatorException: PKIX path building failed".

The reasons this happens is because Apache HTTP Client tries to get the SSLSession and the peer certificate before doing anything else.

Just as a reminder, there are 3 ways of initiating the handshake with an SSLSocket:

  • calling startHandshake which explicitly begins handshakes, or
  • any attempt to read or write application data on this socket causes an implicit handshake, or
  • a call to getSession tries to set up a session if there is no currently valid session, and an implicit handshake is done.

Here are 3 examples, all against a host with a certificate that isn't trusted (using javax.net.ssl.SSLSocketFactory, not the Apache one).

Example 1:

    SSLSocketFactory ssf = (SSLSocketFactory) sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket) ssf.createSocket("untrusted.host.example",
443);
sslSocket.startHandshake();

This throws "javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed" (as expected).

Example 2:

    SSLSocketFactory ssf = (SSLSocketFactory) sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket) ssf.createSocket("untrusted.host.example",
443);
sslSocket.getInputStream().read();

This also throws "javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed" (as expected).

Example 3:

    SSLSocketFactory ssf = (SSLSocketFactory) sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket) ssf.createSocket("untrusted.host.example",
443);
SSLSession sslSession = sslSocket.getSession();
sslSession.getPeerCertificates();

This, however, throws javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated.

This is the logic implemented in Apache HTTP Client's AbstractVerifier used by its org.apache.http.conn.ssl.SSLSocketFactory in version 4.2.1. Later versions make an explicit call to startHandshake(), based on reports in issue HTTPCLIENT-1346.

This ultimately seems to come from the implementation of sun.security. ssl.SSLSocketImpl.getSession(), which catches potential IOExceptions thrown when calling startHandshake(false) (internal method), without throwing it further. This might be a bug, although this shouldn't have a massive security impact, since the SSLSocket will still be closed anyway.

Example 4:

    SSLSocketFactory ssf = (SSLSocketFactory) sslContext.getSocketFactory();
SSLSocket sslSocket = (SSLSocket) ssf.createSocket("untrusted.host.example",
443);
SSLSession sslSession = sslSocket.getSession();
// sslSession.getPeerCertificates();
sslSocket.getInputStream().read();

Thankfully, this will still throw "javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed", whenever you actually try to use that SSLSocket (no loophole there by getting the session without getting the peer certificate).


How to fix this

Like any other issue with certificates that are not trusted, it's a matter of making sure the trust store you're using contains the necessary trust anchors (i.e. the CA certificates that issued the chain you're trying to verify, or possibly the actual server certificate for exceptional cases).

To fix this, you should import the CA certificate (or possibly the server certificate itself) into your trust store. You can do this:

  • in your JRE trust store, usually the cacerts file (that's not necessarily the best, because that would affect all applications using that JRE),
  • in a local copy of your trust store (which you can configure using the -Djavax.net.ssl.trustStore=... options),
  • by creating a specific SSLContext for that connection (as described in this answer). (Some suggest to use a trust manager that does nothing, but this would make your connection vulnerable to MITM attacks.)

Initial answer

javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated

This has nothing to do with trusting certificates or you having to create a custom SSLContext: this is due to the fact that the server isn't sending any certificate at all.

This server is visibly not configured to support TLS properly. This fails (you won't get a remote certificate):

openssl s_client -tls1 -showcerts -connect appserver.gtportalbase.com:443

However, SSLv3 seems to work:

openssl s_client -ssl3 -showcerts -connect appserver.gtportalbase.com:443

If you know who's running this server, it would be worth contacting them to fix this problem. Servers should really support TLSv1 at least nowadays.

Meanwhile, one way to fix this problem would be to create your own org.apache.http.conn.ssl.SSLSocketFactory and use it for this connection with Apache Http client.

This factory would need to create an SSLSocket as usual, use sslSocket.setEnabledProtocols(new String[] {"SSLv3"}); before returning that socket, to disable TLS, which would otherwise be enabled by default.

SSLPeerUnverifiedException while working with HTTPS in android

Here is a sample piece of code for Self-signed certificates for HTTPS connection

    BufferedReader in = null;
HttpsURLConnection client=null;
try {

URL url = new URL(appendedUrl);
client= (HttpsURLConnection) url.openConnection();
client.setRequestMethod("GET");
client.setRequestProperty("Auth-Token", token);
client.setConnectTimeout(120000);
client.setReadTimeout(120000);
if(appendedUrl.contains("https")) {
client.setSSLSocketFactory(certificatePinning(context).getSocketFactory());//for certificate pinning
client.setHostnameVerifier(new HostnameVerifier() {
@Override
public boolean verify(String hostname, SSLSession session) {
if (hostname.equals("YOUR-HOST-ADDRESS"))
return true;
else
return false;
}
});
}
try{
in = new BufferedReader(new InputStreamReader(client.getInputStream()));
}catch(Exception ex)
{
ex.printStackTrace();
}
StringBuffer sb = new StringBuffer("");
String line = "";
String NL = System.getProperty("line.separator");
while ((line = in.readLine()) != null) {
sb.append(line + NL);
}
in.close();

String result = sb.toString();
return new JSONObject(result);
}
finally {
if (in != null) {
try {
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}

SSL Peer Not Authenticated error with HttpClient 4.1

If the server's certificate is self-signed, then this is working as designed and you will have to import the server's certificate into your keystore.

Assuming the server certificate is signed by a well-known CA, this is happening because the set of CA certificates available to a modern browser is much larger than the limited set that is shipped with the JDK/JRE.

The EasySSL solution given in one of the posts you mention just buries the error, and you won't know if the server has a valid certificate.

You must import the proper Root CA into your keystore to validate the certificate. There's a reason you can't get around this with the stock SSL code, and that's to prevent you from writing programs that behave as if they are secure but are not.

Why do I get javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated only in production?

The solution for me ended up being that we were overriding the default java trust store with our own with the java opt. This caused the cert sent by the third party to appear to be invalid since we didn't have any of the default root certs in our myStore.jks.

By adding our self-signed cert into the default java one (/lib/security/cacerts) and removing the java opt, everything was fine.

An alternative would be to add everything in the default java store into your custom store and still use the java opt. Whichever you find more maintainable for your situation.

javax.net.ssl.SSLPeerUnverifiedException: No peer certificate while trying to connect using https with .bks keystore

As Danial said while answering below question,
we should create a custom class from org.apache.http.conn.ssl.SSLSocketFactory, not the one org.apache.http.conn.ssl.SSLSocketFactory itself

Trusting all certificates using HttpClient over HTTPS

Android SSL HttpGet (No peer certificate) error OR (Connection closed by peer) error

The following source should fix your problem.

import android.app.Activity;
import android.widget.EditText;
import android.os.Bundle;
import org.apache.http.HttpResponse;
import org.apache.http.Header
import java.io.InputStream;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import android.util.Log;
import android.view.Menu;
public class MainActivity extends Activity {

private EditText text;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
text = (EditText) findViewById(R.id.editText1);
connect();
}

private void connect(){
try {
DataLoader dl = new DataLoader();
String url = "https://IpAddress";
HttpResponse response = dl.secureLoadData(url);

StringBuilder sb = new StringBuilder();
sb.append("HEADERS:\n\n");

Header[] headers = response.getAllHeaders();
for (int i = 0; i < headers.length; i++) {
Header h = headers[i];
sb.append(h.getName()).append(":\t").append(h.getValue()).append("\n");
}

InputStream is = response.getEntity().getContent();
StringBuilder out = new StringBuilder();
BufferedReader br = new BufferedReader(new InputStreamReader(is));
for (String line = br.readLine(); line != null; line = br.readLine())
out.append(line);
br.close();

sb.append("\n\nCONTENT:\n\n").append(out.toString());

Log.i("response", sb.toString());
text.setText(sb.toString());

} catch (Exception e) {
e.printStackTrace();
}
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.activity_main, menu);
return true;
}

}

import android.app.Application;
import android.content.Context;
import java.io.InputStream;
public class MeaApplication extends Application {

private static Context context;

@Override
public void onCreate() {
super.onCreate();
MeaApplication.context = getApplicationContext();
}

public static Context getAppContext() {
return MeaApplication.context;
}

public static InputStream loadCertAsInputStream() {
return MeaApplication.context.getResources().openRawResource(
R.raw.meacert);
}

}

import org.apache.http.conn.ssl.SSLSocketFactory;
import javax.net.ssl.SSLContext;
import java.security.KeyStore;
import java.security.NoSuchAlgorithmException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.UnrecoverableKeyException;
import javax.net.ssl.TrustManager;
import java.net.Socket;
import java.io.IOException;
import java.net.UnknownHostException;
/**
* Taken from: http://janis.peisenieks.lv/en/76/english-making-an-ssl-connection-via-android/
*
*/
public class CustomSSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");

public CustomSSLSocketFactory(KeyStore truststore)
throws NoSuchAlgorithmException, KeyManagementException,
KeyStoreException, UnrecoverableKeyException {
super(truststore);

TrustManager tm = new CustomX509TrustManager();

sslContext.init(null, new TrustManager[] { tm }, null);
}

public CustomSSLSocketFactory(SSLContext context)
throws KeyManagementException, NoSuchAlgorithmException,
KeyStoreException, UnrecoverableKeyException {
super(null);
sslContext = context;
}

@Override
public Socket createSocket(Socket socket, String host, int port,
boolean autoClose) throws IOException, UnknownHostException {
return sslContext.getSocketFactory().createSocket(socket, host, port,
autoClose);
}

@Override
public Socket createSocket() throws IOException {
return sslContext.getSocketFactory().createSocket();
}
}

import javax.net.ssl.X509TrustManager;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.io.IOException;
import java.io.InputStream;
import java.security.cert.CertificateFactory;
public class CustomX509TrustManager implements X509TrustManager {

@Override
public void checkClientTrusted(X509Certificate[] chain, String authType)
throws CertificateException {
}

@Override
public void checkServerTrusted(java.security.cert.X509Certificate[] certs,
String authType) throws CertificateException {

// Here you can verify the servers certificate. (e.g. against one which is stored on mobile device)

// InputStream inStream = null;
// try {
// inStream = MeaApplication.loadCertAsInputStream();
// CertificateFactory cf = CertificateFactory.getInstance("X.509");
// X509Certificate ca = (X509Certificate)
// cf.generateCertificate(inStream);
// inStream.close();
//
// for (X509Certificate cert : certs) {
// // Verifing by public key
// cert.verify(ca.getPublicKey());
// }
// } catch (Exception e) {
// throw new IllegalArgumentException("Untrusted Certificate!");
// } finally {
// try {
// inStream.close();
// } catch (IOException e) {
// e.printStackTrace();
// }
// }
}

public X509Certificate[] getAcceptedIssuers() {
return null;
}

}

import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.security.KeyManagementException;
import java.net.URISyntaxException;
import java.security.KeyStoreException;
import java.security.UnrecoverableKeyException;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import java.security.SecureRandom;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.client.methods.HttpGet;
public class DataLoader {

public HttpResponse secureLoadData(String url)
throws ClientProtocolException, IOException,
NoSuchAlgorithmException, KeyManagementException,
URISyntaxException, KeyStoreException, UnrecoverableKeyException {
SSLContext ctx = SSLContext.getInstance("TLS");
ctx.init(null, new TrustManager[] { new CustomX509TrustManager() },
new SecureRandom());

HttpClient client = new DefaultHttpClient();

SSLSocketFactory ssf = new CustomSSLSocketFactory(ctx);
ssf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
ClientConnectionManager ccm = client.getConnectionManager();
SchemeRegistry sr = ccm.getSchemeRegistry();
sr.register(new Scheme("https", ssf, 443));
DefaultHttpClient sslClient = new DefaultHttpClient(ccm,
client.getParams());

HttpGet get = new HttpGet(new URI(url));
HttpResponse response = sslClient.execute(get);

return response;
}

}


Related Topics



Leave a reply



Submit