Error in android application: javax.net.ssl.SSLPeerUnverifiedException: No peer certificate - android

Good day, may ask for advice.
My code is worked properly, but one day for no apparent reason and without changes to the code on the server stopped working, displaying this error
I have checked the decisions referred to by links, but none of them gave the desired result.
Perhaps there was something in the SSL protocol?
Safely fixing: javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
javax.net.ssl.sslpeerunverifiedexception no peer certificate
Android ssl: javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
Trusting all certificates using HttpClient over HTTPS
class RequestTask extends AsyncTask<String, String, String> {
#Override
protected String doInBackground(String... params) {
try {
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);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
ResponseHandler<String> res = new BasicResponseHandler();
HttpPost postMethod = new HttpPost("https://api.equalibra.net/banners.json");
nameValuePairs.add(new BasicNameValuePair("lang", "rus"));
postMethod.setEntity(new UrlEncodedFormEntity(nameValuePairs,
HTTP.UTF_8));
String response = "";
try {
response = httpClient.execute(postMethod, res);
} catch (Exception e) {
Log.d("my", e.toString());
}
JSONURL(response);
} catch (Exception e) {
}
return null;
}
#Override
protected void onPostExecute(String result) {
super.onPostExecute(result);
}
#Override
protected void onPreExecute() {
super.onPreExecute();
}
}

The server requires use of SNI (server name indication). Connections not using SNI will simply fail instead of the usual case where they get a default certificate. Since this is a setting on the server side it might have changed recently so that it broke your code.
While SNI is available in newer versions of the Apache HTTP client library it is not available in the version shipped with the Android SDK, which you probably use.

Indeed, the problem was that my Android SDK does not support SNI .
It helped me:

Related

Safely fixing: javax.net.ssl.SSLPeerUnverifiedException: No peer certificate

There are dozens of posts about this issue (javax.net.ssl.SSLPeerUnverifiedException: No peer certificate) but I haven't found anything that works for me.
Many posts (like this, and this) "solve" this by allowing all certificates to be accepted but, of course, this is not a good solution for anything other than testing.
Others seem quite localized and don't work for me. I really hope that someone has some insight that I lack.
So, my problem: I'm testing on a server accessible only through the local network, connecting via HTTPS. Making the call I need to through the browser works fine. No complaining about certificates and if you check the certificates, it all looks good.
When I try on my Android device, I get javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
Here's the code that calls it:
StringBuilder builder = new StringBuilder();
builder.append( /* stuff goes here*/ );
httpGet.setEntity(new UrlEncodedFormEntity(nameValuePairs));
ResponseHandler<String> responseHandler = new BasicResponseHandler();
// Execute HTTP Post Request. Response body returned as a string
HttpClient httpClient = MyActivity.getHttpClient();
HttpGet httpGet = new HttpGet(builder.toString());
String jsonResponse = httpClient.execute(httpGet, responseHandler); //Line causing the Exception
My code for MyActivity.getHttpClient():
protected synchronized static HttpClient getHttpClient(){
if (httpClient != null)
return httpClient;
HttpParams httpParameters = new BasicHttpParams();
HttpConnectionParams.setConnectionTimeout(httpParameters, TIMEOUT_CONNECTION);
HttpConnectionParams.setSoTimeout(httpParameters, TIMEOUT_SOCKET);
HttpProtocolParams.setVersion(httpParameters, HttpVersion.HTTP_1_1);
//Thread safe in case various AsyncTasks try to access it concurrently
SchemeRegistry schemeRegistry = new SchemeRegistry();
schemeRegistry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
schemeRegistry.register(new Scheme("https", SSLSocketFactory.getSocketFactory(), 443));
ClientConnectionManager cm = new ThreadSafeClientConnManager(httpParameters, schemeRegistry);
httpClient = new DefaultHttpClient(cm, httpParameters);
CookieStore cookieStore = httpClient.getCookieStore();
HttpContext localContext = new BasicHttpContext();
localContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
return httpClient;
}
Any help would be much appreciated.
Edit
Also just to mention I've had other SSL issues with another app but adding the SchemeRegistry portion fixed it for me before.
Edit 2
So far I've only tested on Android 3.1, but I need this to work on Android 2.2+ regardless. I just tested on the browser on my Android tab (Android 3.1) and it complains about the certificate. It's fine on my pc browser, but not on the Android browser or in my app.
Edit 3
Turns out the iOS browser also complains about it. I'm starting to think it's a certificate chain issue described here (SSL certificate is not trusted - on mobile only)
It turns out my code was fine and the problem was that the server was not returning the full certificate chain. For more information see this SO post and this superuser post:
SSL certificate is not trusted - on mobile only
https://superuser.com/questions/347588/how-do-ssl-chains-work
Try below code :-
BasicHttpResponse httpResponse = null;
HttpPost httppost = new HttpPost(URL);
HttpParams httpParameters = new BasicHttpParams();
// Set the timeout in milliseconds until a connection is
// established.
int timeoutConnection = ConstantLib.CONNECTION_TIMEOUT;
HttpConnectionParams.setConnectionTimeout(httpParameters,
timeoutConnection);
// Set the default socket timeout (SO_TIMEOUT)
// in milliseconds which is the timeout for waiting for data.
int timeoutSocket = ConstantLib.CONNECTION_TIMEOUT;
HttpConnectionParams
.setSoTimeout(httpParameters, timeoutSocket);
DefaultHttpClient httpClient = new DefaultHttpClient(
httpParameters);
List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>();
nameValuePairs.add(new BasicNameValuePair(ConstantLib.locale,
locale));
In my case everything used to work fine. Suddenly after 2 days my device did not show any https site or image link.
After some investigation it turns out that My time settings was not up to date on device.
I changed my time settings properly and it worked.
I had this exception when I used self-signed certificate + ip address. Just add these lines
HostnameVerifier allHostsValid = new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
};
HttpsURLConnection.setDefaultHostnameVerifier(allHostsValid);
and your HttpURLConnection will work.
That trick is not related to validation against CA! So if I specify wrong CA and use that trick, I will get another exception. So the host remains trusted
Just in case, I will leave code for specifying your own CA here:
String certStr = context.getString(R.string.caApi);
X509Certificate ca = SecurityHelper.readCert(certStr);
TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
ks.load(null);
ks.setCertificateEntry("caCert", ca);
tmf.init(ks);
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, tmf.getTrustManagers(), null);
HttpsURLConnection.setDefaultSSLSocketFactory(sslContext.getSocketFactory());
Do not forget to use cool feature buildTypes and place different CAs for debug/release in res folder.

javax.net.ssl.sslpeerunverifiedexception no peer certificate

I am trying to insert a record into MySQL by posting data to a PHP server from an Android app. I have added the INTERNET permission to AndroidManifest.xml
I get javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
Android code
private void senddata(ArrayList<NameValuePair> data)
{
try
{
HttpClient httpclient = new DefaultHttpClient();
HttpPost httppost = new HttpPost("https://10.0.2.2/insert222.php");
httppost.setEntity(new UrlEncodedFormEntity(data));
HttpResponse response = httpclient.execute(httppost);
}
catch (Exception e) {
// TODO: handle exception
Log.e("log_tag", "Error: "+e.toString());
}
}
Can anyone help?
Warning: Do not implement this in production code you are ever going to use on a network you do not entirely trust. Especially anything going over the public internet. This link gives more correct answer. Here is an implementation using SSL.
Your problem is you are using DefaultHttpClient for https(secure url).
Create a custom DefaultHttpClient
public static HttpClient createHttpClient()
{
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.DEFAULT_CONTENT_CHARSET);
HttpProtocolParams.setUseExpectContinue(params, 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(params, schReg);
return new DefaultHttpClient(conMgr, params);
}
Than change your code as follows:
HttpClient httpclient = createHttpClient();
HttpPost httppost = new HttpPost("https://10.0.2.2/insert222.php");
httppost.setEntity(new UrlEncodedFormEntity(data));
HttpResponse response = httpclient.execute(httppost);
Have a look at here if you have problems
It should work.
I had this issue with an IIS 8 server. In the https binding, I had to uncheck the checkbox labeled "Require Server Name Indication." Once I unchecked it, I quit getting the error.
I have to say all trusted certificates (trusted by authorized centres such as COMODO, Symantec, etc.) have to be work in any case. If your app recieves such javax.net.ssl.SSLPeerUnverifiedException: No peer certificate using bought certificate you give something wrong on server side.
To test use openssl s_client -connect example.com:443 command to get inner information about certificate your app recieve.
In may case my nginx-server sent wrong certificate in some cases.

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!

Connect to HTTPS from Android - REST and SOAP web service

I am facing a problem to call https from Android. Can any one please help with steps to connect to the https server.
I tried to connect to google with https and its working fine but when I try to connect to my local server, I am facing problems.
want to connect a RESTful web service with https
want to connect a SOAP based web service developed using JAX-WS with https.
Code to connect with RESTFul
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);
// Example send http request
//final String url = "https://encrypted.google.com/";
final String url = "https://ipaddress:8181/RESTTest/cars";
HttpPost httpPost = new HttpPost(url);
try{
HttpResponse response = httpClient.execute(httpPost);
System.out.println(response);
}catch(Exception e){
e.printStackTrace();
}
its working fine for google but not working for my server and it's giving
javax.net.ssl.SSLException: Not trusted server certificate
Code for connect with SOAP:
public String getString(final String methodName, Map<String, Object> params) throws Exception {
HttpTransportSE httpsTransportSE = new HttpTransportSE("https://ipaddress:8181/BankingWS/banking?wsdl");
try {
SoapObject request = new SoapObject("https://test/",
methodName);
if(params != null && params.size() > 0){
Set<String> keys = params.keySet();
Iterator<String> iterator = keys.iterator();
while(iterator.hasNext()){
String key = iterator.next();
request.addProperty(key, params.get(key));
key = null;
}
}
SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
TrustManagerManipulator.allowAllSSL();
httpsTransportSE.call(methodName, envelope);
SoapPrimitive sp = (SoapPrimitive) envelope.getResponse();
return sp.toString();
} catch (Exception exception) {
System.out.println(exception.toString());
throw exception;
}
}
In above code using the TrustManagerManipulator from following link:
http://abhinavasblog.blogspot.com/2011/07/allow-untrusted-certificate-for-https.html
This is also not working and when I check the response code it's giving
SoapFault - faultcode: 'S:Client' faultstring: 'Cannot find dispatch method for {test.WSEndPointPort}authenticate' faultactor: 'null' detail: null
Please help to fix this problem, as I am not able to call https from Android by any way :(
Thank you very much for your time and efforts.
Thank you,
Ishan
You need to create a X509TrustManager which bypass all the security check. You can find an example in this similar questions:
Make a connection to a HTTPS server from Java and ignore the validity of the security certificate
or
How to ignore SSL certificate errors in Apache HttpClient 4.0

Performing login to https website via Android app

First off, I'm pretty newb at this. I'm new to Android, to asp, to javascript, to http even.
I'm trying to build an Android app that allows me to login to my school's website and pull data off it, ultimately I hope to do something like insert my timetable's data into Android's calendar entries. However I'm having trouble logging in.
Here's the website:
https://sso.wis.ntu.edu.sg/webexe88/owa/sso_login2.asp
What I'm doing currently is doing a http POST to the above-mentioned URL and I'm hoping to be redirected to hhttps://wish.wis.ntu.edu.sg/pls/webexe/aus_stars_check.check_subject_web2 which will display my timetable.
So far my code is as follows after viewing the webpage's source and searching quite a bit on the Internet:
private void start_login(String[] array) {
// TODO Auto-generated method stub
Toast.makeText(this, "Logging in...", Toast.LENGTH_LONG).show();
WebView wv = new WebView(this);
this.setContentView(wv);
try {
ArrayList<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(4);
nameValuePairs.add(new BasicNameValuePair("UserName", <my username here>));
nameValuePairs.add(new BasicNameValuePair("PIN", <my password here>));
nameValuePairs.add(new BasicNameValuePair("Domain", "STUDENT"));
nameValuePairs.add(new BasicNameValuePair("p2", "https://wish.wis.ntu.edu.sg/pls/webexe/aus_stars_check.check_subject_web2"));
wv.loadData(CustomHttpClient.executeHttpPost(URL, nameValuePairs), "text/html", "utf-8");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}// end start_login
That's the login function.
The CustomHttpClient I'm using is thanks to this guy: http://www.newtondev.com/2010/07/27/making-http-requests-using-google-android/
So far I'm not getting any results. What am I doing wrong? Am I missing values in the ArrayList, or have I got the URL all wrong?
Below code handles https and gives httpsclient for https url .. you need httpsclient to make request to https urls.
Might below code is of help to you:
public DefaultHttpClient getClient()
{
DefaultHttpClient ret = null;
//sets up parameters
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, "utf-8");
params.setBooleanParameter("http.protocol.expect-continue", false);
//registers schemes for both http and https
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
final SSLSocketFactory sslSocketFactory = SSLSocketFactory.getSocketFactory();
sslSocketFactory.setHostnameVerifier(SSLSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
registry.register(new Scheme("https", sslSocketFactory, 443));
ThreadSafeClientConnManager manager = new ThreadSafeClientConnManager(params, registry);
ret = new DefaultHttpClient(manager, params);
return ret;
}

Categories

Resources