Issue with SSL certificate: "No peer certificate" - android

I'm trying to authenticate through Last.fm's API.
On Android 4.3 it works just by doing
HttpPost post = new HttpPost("https://ws.audioscrobbler.com/2.0/");
post.setEntity(new UrlEncodedFormEntity(params));
HttpClient client = new DefaultHttpClient();
HttpResponse response = client.execute(post);
but on 2.3.3 I get
javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
Then I tried the solution given here:
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
DefaultHttpClient client = new DefaultHttpClient();
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams());
// Set verifier
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
HttpPost post = new HttpPost("https://ws.audioscrobbler.com/2.0/");
post.setEntity(new UrlEncodedFormEntity(params));
HttpResponse response = httpClient.execute(post);
but I still get the same error.
Then I tried that:
HttpParams httpParams = new BasicHttpParams();
HttpProtocolParams.setVersion(httpParams, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(httpParams, HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(httpParams, true);
SchemeRegistry schReg = new SchemeRegistry();
schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schReg.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ClientConnectionManager conMgr = new ThreadSafeClientConnManager(httpParams, schReg);
DefaultHttpClient httpClient = new DefaultHttpClient(conMgr, httpParams);
HttpPost post = new HttpPost("https://ws.audioscrobbler.com/2.0/");
post.setEntity(new UrlEncodedFormEntity(params));
HttpResponse response = httpClient.execute(post);
and failed again.
Anybody can help?

There seems to be some problem with the way the certificates are returned from the server OR may be android system keystore does not have the relevant root certs to validate and complete the handshake.
Looking at the certificate chain information for the site mentioned in the question, it seems to me that the chain is not correctly sorted.
You can try the answer here

Related

Getting SSLPeerUnverifiedException in Android

i am getting SSL Peer Unverified Exception when i try to connect using HTTPs Connection.
I am new to HTTPs.
My code is :
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
DefaultHttpClient client = new DefaultHttpClient();
SchemeRegistry registry = new SchemeRegistry();
SSLSocketFactory socketFactory = SSLSocketFactory.getSocketFactory();
socketFactory.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
registry.register(new Scheme("https", socketFactory, 443));
SingleClientConnManager mgr = new SingleClientConnManager(client.getParams(), registry);
DefaultHttpClient httpClient = new DefaultHttpClient(mgr, client.getParams()); HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
HttpPost httppost = new HttpPost("https://server.example.com/Login");
List<BasicNameValuePair> nameValuePairs = new ArrayList<BasicNameValuePair>(
2);
nameValuePairs.add(new BasicNameValuePair("LoginId",uname));
nameValuePairs.add(new BasicNameValuePair("Password",pass));
try {
httppost.setEntity(new UrlEncodedFormEntity(nameValuePairs));
HttpResponse response = httpClient.execute(httppost);
if (response.getStatusLine().getStatusCode() == 200) {
}
Log.i("zacharia", "Response :"+EntityUtils.toString(response.getEntity()));
} catch (Exception e) {
}
The SSL Peer Unverified Exception could be thrown for several reasons, the most common is when the certificate sent by the server is a self signed certificate and not a certificate signed by authorized CA, if that's the issue the common approach in android is adding the certificate to the Trusted Certificates chain and then making the request as follows:
KeyStore selfsignedKeys = KeyStore.getInstance("BKS");
selfsignedKeys.load(context.getResources().openRawResource(R.raw.selfsignedcertsbks),
"genericPassword".toCharArray());
TrustManagerFactory trustMgr = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustMgr.init(selfsignedKeys);
SSLContext selfsignedSSLcontext = SSLContext.getInstance("TLS");
selfsignedSSLcontext.init(null, trustMgr.getTrustManagers(), new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(selfsignedSSLcontext.getSocketFactory());
URL serverURL = new URL("https://server.example.com/endpointTest");
HttpsURLConnection serverConn = (HttpsURLConnection)serverURL.openConnection();
Take on count that this approach is only when you are sure the certificate not signed by a CA, and in order to make it work you need to have the certificate it self, put it in a BKS keystore (for android to read it) and then open an HttpURLConnection using the SSL context that "accepts" that self signed certificate, because the DefaultHttpClient will not handle those requests based on the Default SSLContext.
If you want to learn more about SSL i recommend you to read the book "Application Security for the Android Platform" by Jeff Six Editorial O'Reilly...
Regards!

Calling WCF from android over https with credentials

I am trying to call my RESTful WCF service over https on Android. I keep getting a 401: unauthorized error whenever I make the call. The other parts of my code work, ive tested it locally.
Here is the pertinent code:
// http scheme
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// https scheme
schemeRegistry.register(new Scheme("https", new EasySSLSocketFactory(), 443));
credentialsProvider = new BasicCredentialsProvider();
credentialsProvider.setCredentials(new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT),
new UsernamePasswordCredentials("user", "pass"));
clientConnectionManager = new ThreadSafeClientConnManager(params, schemeRegistry);
context = new BasicHttpContext();
context.setAttribute("http.auth.credentials-provider", credentialsProvider);
HttpGet request = new HttpGet(SERVICE_URI + URL1 + EID);
request.setHeader("Accept", "application/json");
request.setHeader("Content-type", "application/json");
DefaultHttpClient client = new DefaultHttpClient(clientConnectionManager, params);
client.setCredentialsProvider(credentialsProvider);
HttpResponse response = client.execute(request, context);
HttpEntity responseEntity = response.getEntity();
EasySSLSocketFactory uses an implementation of X509TrustManager. I know that code works as well. Can someone please provide some advice. Nothing I have found works correctly.
Turns out, HttpClient doen't support NTLM authentication out of the box (im using IIS with windows auth). This link gave me everything I needed. Just copy and paste and forget about it.
http://hc.apache.org/httpcomponents-client-ga/ntlm.html

Make execute() of HttpDefaultClient very slow

I have massive performance problems with the execute method of the execute() method of the HttpDefaultClient.
I'm currently using this to post data to a Server, receiving JSON and deserialize the data. A call takes 8s to 30s on my phone. If I switch to Wifi (it's pretty fast, the same call takes 300ms on my PC) it takes 3s to 8s. At least 90% of that time is spend in the execute method.
Is use this code:
HttpPost post = new HttpPost(DEST_URL);
HashMap<String, String> params = req.getPostParams();
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
for (String key : params.keySet()) {
nameValuePairs.add(new BasicNameValuePair(key, params.get(key)));
}
post.setEntity(new UrlEncodedFormEntity(nameValuePairs));
post.setHeader(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
HttpResponse response = httpClient.execute(post); // very slow!
return response;
We also develop an iOS app which is able to do the same within 1 to 2s. Is there a quicker way for http (https in the future)?
Creating the client like this:
HostnameVerifier hostnameVerifier = org.apache.http.conn.ssl.SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER;
final SSLSocketFactory socketFactory = SSLSocketFactory
.getSocketFactory();
socketFactory
.setHostnameVerifier((X509HostnameVerifier) hostnameVerifier);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", socketFactory, 443));
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
HttpClient client = new DefaultHttpClient(params);
Using: HTC Wildfire, Android 2.2.1
codes above works fine.
if i create an httpclient the following way:
DefaultHttpClient httpClient = new DefaultHttpClient();
// httpclient
httpClient.getParams().setParameter(
CoreConnectionPNames.CONNECTION_TIMEOUT, mConnectionTimeOut);
httpClient.getParams().setParameter(CoreConnectionPNames.SO_TIMEOUT,
mSocketTimeOut);
for first time to post data to server and got response , it cost me 10--20 seconds.
but if i create an HttpClient following the answer above.
when first time to post data to server and got response , it cost just 4 seconds,and i think it works fine .

HTTPS In Android

I have implemented HTTP Post to post data to the backend. How do I implement HTTPS in Android (I have already configured the backend for https)?
I googled and found some solutions:
Secure HTTP Post in Android
and tried them but I do not receive any data in the backend.
Is it the correct way to implement? Is there any other method?
Below is my code snippet:
File file = new File(filepath);
HttpClient client = new DefaultHttpClient();
//String url = "http://test.....;
String url = "https://test......";
HttpPost post = new HttpPost(url);
FileEntity bin = new FileEntity(file, url);
post.setEntity(bin);
HttpResponse response = client.execute(post);
HttpEntity resEntity = response.getEntity();
Basically I am using fileentity to do a HTTPPost. Now I want to do this over https. After implementing https over at the backend I just modified http to https in the url and tested again. And it is not working.
Any idea how do i resolve this?
Thanks In Advance,
Perumal
Make sure your http client supports the SSL socket:
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
HttpParams params = new BasicHttpParams();
ClientConnectionManager manager = new ThreadSafeClientConnManager(params, schemeRegistry);
HttpClient httpsClient = new DefaultHttpClient(manager, params);
and use this client to execute your POST request:
HttpPost post = new HttpPost("https://www.mysecuresite.com");
post.setHeader("Content-Type", "application/x-www-form-urlencoded");
post.setEntity(new StringEntity("This is the POST body", HTTP.UTF_8));
HttpResponse response = httpsClient.execute(post);

Android and SSL - checking certificate validity

I've got the following code making SSL work with my HttpClient connections and such
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("https",
SSLSocketFactory.getSocketFactory(), 443));
HttpParams params = new BasicHttpParams();
SingleClientConnManager mgr = new SingleClientConnManager(params, schemeRegistry);
HttpClient client = new DefaultHttpClient(mgr, params);
However, does this actually validate the cert? It seems like there should be more to it.
Nevermind, the above code does indeed validate the certificate. I tried it with some random self signed certs for different sites, and it failed.

Categories

Resources