Android. SSLHandshakeException Connection reset by peer in AsyncHttpClient or Retrofit - android

Does someone know what can be wrong in configuration, that I getting such exception:
javax.net.ssl.SSLHandshakeException: SSL handshake aborted: ssl=0x71c528b200:
I/O error during system call, Connection reset by peer
And how to configure this for AsyncHttpClient (com.loopj.android:android-async-http:1.4.9)?
I am using the next configuration:
import com.loopj.android.http.AsyncHttpClient;
import com.loopj.android.http.AsyncHttpResponseHandler;
import com.loopj.android.http.PersistentCookieStore;
import com.loopj.android.http.MySSLSocketFactory;
import cz.msebera.android.httpclient.Header;
import cz.msebera.android.httpclient.message.BasicHeader;
public class ProductsRestService {
public AsyncHttpClient getHttpClient() {
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
asyncHttpClient.setCookieStore(new PersistentCookieStore(getContext()));
KeyStore trustStore;
try {
trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
MySSLSocketFactory socketFactory = new MySSLSocketFactory(trustStore);
socketFactory.setHostnameVerifier(AppSSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
asyncHttpClient.setSSLSocketFactory(socketFactory);
} catch (Exception e) {
}
asyncHttpClient.setURLEncodingEnabled(true);
return asyncHttpClient;
}
}
I have found that this is probably different versions of TLS, but then not sure how to configure Async client.
The same I have tried for Retrofit:
Retrofit.Builder builder = new Retrofit.Builder()
.baseUrl(HOST)
.addConverterFactory(GsonConverterFactory.create());
Retrofit retrofit = builder.build();
RetrofitCallService callTokenService = retrofit.create(RetrofitCallService.class);
Call<String> tokens = callTokenService.getToken();
Headers headers = null;
try {
headers = tokens.execute().headers();
} catch (IOException e) {
e.printStackTrace();
}
List<String> values = headers.values("Content-Type");
Result the same exception. Not really sure in which direction I should search.
Thanks a lot for any help!

Related

Use a certificate in an okhttp request with android

The server of the application in which I work uses a certificate to allow requests.
I have it installed, for example, in the desktop Chrome browser and it works fine. It´s a usual certificate with the extension .cer
Now I have to make this certificate work also in my android application and, honestly, I have never done it and I'm a bit lost.
To make the requests I am using okhttp2, as you can see in this example:
public String makeServiceCall(String url, JSONObject data) {
final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
OkHttpClient client = new OkHttpClient();
client.setConnectTimeout(45, TimeUnit.SECONDS);
client.setReadTimeout(45, TimeUnit.SECONDS);
client.setProtocols(Arrays.asList(Protocol.HTTP_1_1));
RequestBody body = RequestBody.create(JSON, data.toString());
Request request = new Request.Builder()
.url(url)
.header("Accept","application/json")
.post(body)
.build();
try {
Response response = client.newCall(request).execute();
return response.body().string();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
So far everything works perfectly, but after searching and reading tutorials, examples, etc, (many of them from this page) I have not managed to make it work. Make it work with the certificate.
Having never done this, and being a bit confused already, I would appreciate the following clarifications:
The certificate in .cer format that I have, I suppose I should convert it to another format to be able to use it in android ...
Is it correct? If it is correct, how should I do it?
ok, I already have my certificate converted to BKS and hosted in the res / raw folder, but I'm still unable to apply it successfully to the request okhttp2 ..
Once with a certificate in correct format,
How is it implemented with the requests that I am already making in the code that I have set as an example?
I have searched for information about doing it using okhttp3 but I have not been able to authorize the requests either.
This article has been useful to me, but I am not using retrofit and adapting it to okhttp2 does not work either.
I would appreciate an explanation of how to do it
Here is an implementation using official okhttp3 sample code. It is possible to create a trusted OkHttpClient using a custom certificate. I've put the .cer certificate in res/raw then read it in using the trustedCertificatesInputStream() method.
CustomTrust customTrust = new CustomTrust(getApplicationContext());
OkHttpClient client = customTrust.getClient();
CustomTrust.java
import android.content.Context;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Arrays;
import java.util.Collection;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
import okhttp3.CertificatePinner;
import okhttp3.OkHttpClient;
public final class CustomTrust {
private final OkHttpClient client;
private final Context context;
public CustomTrust(Context context) {
this.context = context;
X509TrustManager trustManager;
SSLSocketFactory sslSocketFactory;
try {
trustManager = trustManagerForCertificates(trustedCertificatesInputStream());
SSLContext sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{trustManager}, null);
sslSocketFactory = sslContext.getSocketFactory();
} catch (GeneralSecurityException e) {
throw new RuntimeException(e);
}
client = new OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.connectTimeout(45, TimeUnit.SECONDS)
.readTimeout(45, TimeUnit.SECONDS)
.protocols(Arrays.asList(Protocol.HTTP_1_1))
.build();
}
public OkHttpClient getClient() {
return client;
}
/**
* Returns an input stream containing one or more certificate PEM files. This implementation just
* embeds the PEM files in Java strings; most applications will instead read this from a resource
* file that gets bundled with the application.
*/
private InputStream trustedCertificatesInputStream() {
return context.getResources().openRawResource(R.raw.certificate);
}
/**
* Returns a trust manager that trusts {#code certificates} and none other. HTTPS services whose
* certificates have not been signed by these certificates will fail with a {#code
* SSLHandshakeException}.
*
* <p>This can be used to replace the host platform's built-in trusted certificates with a custom
* set. This is useful in development where certificate authority-trusted certificates aren't
* available. Or in production, to avoid reliance on third-party certificate authorities.
*
* <p>See also {#link CertificatePinner}, which can limit trusted certificates while still using
* the host platform's built-in trust store.
*
* <h3>Warning: Customizing Trusted Certificates is Dangerous!</h3>
*
* <p>Relying on your own trusted certificates limits your server team's ability to update their
* TLS certificates. By installing a specific set of trusted certificates, you take on additional
* operational complexity and limit your ability to migrate between certificate authorities. Do
* not use custom trusted certificates in production without the blessing of your server's TLS
* administrator.
*/
private X509TrustManager trustManagerForCertificates(InputStream in)
throws GeneralSecurityException {
CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
if (certificates.isEmpty()) {
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
}
// Put the certificates a key store.
char[] password = "password".toCharArray(); // Any password will work.
KeyStore keyStore = newEmptyKeyStore(password);
int index = 0;
for (Certificate certificate : certificates) {
String certificateAlias = Integer.toString(index++);
keyStore.setCertificateEntry(certificateAlias, certificate);
}
// Use it to build an X509 trust manager.
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
KeyManagerFactory.getDefaultAlgorithm());
keyManagerFactory.init(keyStore, password);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init(keyStore);
TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
throw new IllegalStateException("Unexpected default trust managers:"
+ Arrays.toString(trustManagers));
}
return (X509TrustManager) trustManagers[0];
}
private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {
try {
KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
InputStream in = null; // By convention, 'null' creates an empty key store.
keyStore.load(in, password);
return keyStore;
} catch (IOException e) {
throw new AssertionError(e);
}
}
}
Although an answer has already been provided, which is good and works perfect, I would like to provide an alternative which requires less custom code.
InputStream trustedCertificatesAsInputStream = context.getResources().openRawResource(R.raw.certificate);
List<Certificate> trustedCertificates = CertificateUtils.loadCertificate(trustedCertificatesAsInputStream);
SSLFactory sslFactory = SSLFactory.builder()
.withTrustMaterial(trustedCertificates)
.build();
SSLSocketFactory sslSocketFactory = sslFactory.getSslSocketFactory();
X509ExtendedtrustManager trustManager = sslFactory.getTrustManager().orElseThrow();
OkHttpClient okHttpClient = OkHttpClient.Builder()
.sslSocketFactory(sslSocketFactory, trustManager)
.build();
The above library is maintained by me and you can find it here: GitHub - SSLContext Kickstart

How do you encrypt / hide the body of an HTTPS call using Retrofit 2 + OkHttp 3?

I am currently working on a project where I am sending data via an https call to our server api. The base URL for the project supports ssl (Our url api endpoint starts with https://api.....). I am using Retrofit 2 and OkHttp3 and am setting up the client like this:
public static void buildClient(){
//Misc code here.... not showing for security reasons.
OkHttpClient client = RetrofitClient.configureClient(new OkHttpClient());
//I make calls here to update interceptors, timeouts, etc.
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(BASE_URL)
.addConverterFactory(GsonConverterFactory.create(new Gson()))
.client(client)
.build();
}
//Setup the ssl stuff here
public static OkHttpClient configureClient(final OkHttpClient client) {
final TrustManager[] certs = new TrustManager[]{new X509TrustManager() {
#Override
public X509Certificate[] getAcceptedIssuers() {
return null;
}
#Override
public void checkServerTrusted(final X509Certificate[] chain,
final String authType)
throws CertificateException {
}
#Override
public void checkClientTrusted(final X509Certificate[] chain,
final String authType)
throws CertificateException {
}
}};
SSLContext ssl = null;
try {
ssl = SSLContext.getInstance("TLS");
ssl.init(null, certs, new SecureRandom());
} catch (final java.security.GeneralSecurityException ex) {
}
try {
final HostnameVerifier hostnameVerifier = new HostnameVerifier() {
#Override
public boolean verify(final String hostname,
final SSLSession session) {
return true;
}
};
client.setHostnameVerifier(hostnameVerifier);
client.setSslSocketFactory(ssl.getSocketFactory());
} catch (final Exception e) {
}
return client;
}
So after this, we are all set.
Now, here's what I know:
1) I am sending via HTTPS because if I were not, the server would throw an error, which it is not.
2) My code is working just fine in that it is communicating with the server and the app will work.
The problem here is that the actual Body data is not being encrypted. Here are 2 photo examples to show what I mean.
1)
2)
The first image shows proper obfuscation of the actual body data in that the data is being converted to encrypted 'stuff' while the second shows plain text. The second one is me sending a POST call to the server with an object.
My question is, how do I go about replicating this so that my body text is hidden / encrypted like the other?
Notes:
1) I am using obfuscation via Proguard
2) I to have minifyEnabled set to true
3) How I found this out is via a packet sniffer
Anyone have any ideas how to accomplish this? Or can anyone point me in the right direction as to what this is called specifically?
Thanks.
EDIT:
So, it looks like I was not understanding a key component here.
Short answer is, the call is already encrypted and is sending Https.
Long answer is, I have been comparing my data calls to ones like these:
1)
2)
Where I just assumed that These were encrypted, while mine was not. It turns out that the calls I am sending are encrypted just fine, as are these, but this data is zipped / compressed, which makes it unreadable to the eye, which is what made me think that it was what encrypted data looked like from a packet sniffer.
Your question is: Why I use HTTPS but the Packet Capture or Charles can view all of the SSL / HTTPS traffic between the client and the Internet?
Because the Packet Capture(the VPN proxy) or Charles cheated your client as an intermediary:
Your client <--> Packet Capture/Charles <--> Your target server.
So the proxy tool can view all your HTTPS content(In fact they are indeed encrypted).
Solution:
You can refer the OkHttp wiki: https://github.com/square/okhttp/wiki/HTTPS
and set a Certificate pinning for your HTTPS checking. For example:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
final TextView textView = (TextView) findViewById(R.id.text);
ConnectionSpec spec = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
.tlsVersions(TlsVersion.TLS_1_2)
.cipherSuites(
CipherSuite.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
CipherSuite.TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
.build();
OkHttpClient client = new OkHttpClient.Builder()
.connectionSpecs(Collections.singletonList(spec))
.certificatePinner(new CertificatePinner.Builder()
.add("drakeet.me", "sha256/gGOcYKAwzEaUfun6YdxZvFSQq/x2lF/R8UizDFofveY=")
.build())
.build();
Request request = new Request.Builder()
.url("https://drakeet.me?s=type")
.post(RequestBody.create(MediaType.parse("text"), "xxx...xxx"))
.addHeader("token", "xxx")
.build();
final Handler handler = new Handler();
client.newCall(request).enqueue(new Callback() {
#Override public void onFailure(Call call, IOException e) {
e.printStackTrace();
}
#Override public void onResponse(Call call, final Response response)
throws IOException {
final String t = response.body().string();
handler.post(new Runnable() {
#Override public void run() {
textView.setText(t);
}
});
}
});
}
}
As my above codes, I preset a certificatePinner relate to the true certificatePinner of my target server, so that if I use Packet Capture/Charles now, they will create a false certificatePinner by themselve, and OkHttp will compare the two pinning, if not equal, throw a javax.net.ssl.SSLPeerUnverifiedException: Certificate pinning failure!
And if you close the Packet Capture/Charles, the exception dismiss and send HTTPS content successfully.
You might see, that requests are still made using "http". Use different Retrofit.Builder method baseUrl(HttpUrl):
HttpUrl httpUrl = new HttpUrl.Builder()
.host(BASE_URL)
.scheme("https").build();
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(httpUrl)
.build();

SSL connection reusing and caching with Android OkHttpClient

I am using Retrofit and OkHttp to perform all network operations like GET, POST for both HTTP and HTTPS url. Everything is working fine but except that i have a requirement to reuse the sessions in order to reduce the Handshake timing process for each and every service calls. As of now the server takes more than 800ms to initiate the handshake between client and server for all the service calls.
What I need:
I have to reuse the SSLSessions in order to make handshake happen only for the first time or during specific intervals.
Code I am using for SSL using Okhttp and Retrofit:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(baseURL)
.addConverterFactory(GsonConverterFactory.create())
.client(getOkHttpClient(context, new OkHttpClient(), context.getResources().openRawResource(R.raw.mysslcertificate)))
.build();
retrofit.create(apiClass);
public static OkHttpClient getOkHttpClient(Context context,OkHttpClient client, InputStream inputStream) {
try {
if (inputStream != null) {
SSLContext sslContext = sslContextForTrustedCertificates(inputStream);
if (sslContext != null) {
client = client.newBuilder()
.sslSocketFactory(sslContext.getSocketFactory()).build();
else {
CLog.i(Constants.LOG_TAG_HTTPLIBRARY,"GZip not done because it is not a Analytics data");
client = client.newBuilder()
.sslSocketFactory(sslContext.getSocketFactory()).build();
}
}
}
} catch (Exception e) {
e.printStackTrace();
}
return client;
}
private static SSLContext sslContextForTrustedCertificates(InputStream in) {
try {
CertificateFactory e = CertificateFactory.getInstance("X.509");
Collection certificates = e.generateCertificates(in);
if (certificates.isEmpty()) {
throw new IllegalArgumentException("expected non-empty set of trusted certificates");
} else {
char[] password = "password".toCharArray();
KeyStore keyStore = newEmptyKeyStore(password);
int index = 0;
Iterator keyManagerFactory = certificates.iterator();
while (keyManagerFactory.hasNext()) {
Certificate trustManagerFactory = (Certificate) keyManagerFactory.next();
String sslContext = Integer.toString(index++);
keyStore.setCertificateEntry(sslContext, trustManagerFactory);
}
KeyManagerFactory var10 = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm());
var10.init(keyStore, password);
TrustManagerFactory var11 = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
var11.init(keyStore);
SSLContext var12 = SSLContext.getInstance("TLS");
var12.init(var10.getKeyManagers(), var11.getTrustManagers(), new SecureRandom());
return var12;
}
} catch (Exception var9) {
var9.printStackTrace();
}
return null;
}
What I have tried:
Since i couldn't find anything related to OkHttpClient but i tried referring few of the solutions like from the link as follows:
https://gist.github.com/codebutler/5565971
https://developer.android.com/reference/javax/net/ssl/SSLContext.html
But to be very frank nothing was helpful to me and I couldn't even find any relavant solutions for my requirement. In turn finally, I am completely stuck with this solution for the couple of weeks. Kindly help me to achieve my tasks through any of your tips and suggestions. Any piece of code or approach will be very useful to me. Thanks in advance.

SSL Certificate Pinning w/ Picasso

I am using Picasso to cache Images. Our backend recently switched to HTTPS using self signed certificate pinning as authentication. I used the khandroid library to create an HTTP client that pins the certificates to each request; basically following this example.
http://ogrelab.ikratko.com/using-android-volley-with-self-signed-certificate/
I now need to apply this same concept to Picasso but am unsure how to modify Picasso's singleton to use pinned SSL certificates.
Turns out I was Just looking in the wrong place. I was attempting to modify the OkHttpDownloader, but I needed to modify the OkHttpClient. Here is some sample code.
public static Picasso getInstance(Context context) {
if (sPicasso == null) {
InputStream keyStore = context.getResources().openRawResource(R.raw.my_keystore);
Picasso.Builder builder = new Picasso.Builder(context);
OkHttpClient okHttpClient = new OkHttpClient();
SSLContext sslContext;
try {
sslContext = SSLContext.getInstance("TLS");
sslContext.init(null, new TrustManager[]{new SsX509TrustManager(keyStore, password)}, null);
okHttpClient.setSslSocketFactory(sslContext.getSocketFactory());
OkHttpDownloader okHttpDownloader = new OkHttpDownloader(okHttpClient);
builder.downloader(okHttpDownloader);
sPicasso = builder.build();
} catch (NoSuchAlgorithmException e) {
throw new IllegalStateException("Failure initializing default SSL context", e);
} catch (KeyManagementException e) {
throw new IllegalStateException("Failure initializing default SSL context", e);
} catch (GeneralSecurityException e) {
e.printStackTrace();
}
}
return sPicasso;
}

Making a HTTPS request using Android Volley

I am trying to make a https request using this code:
RequestQueue queue = Volley.newRequestQueue(getApplicationContext());
request = new Request<String>(Request.Method.GET,"https://devblahblahblah.com/service/etc",errListener);
but I am getting this error:
com.android.volley.NoConnectionError:
javax.net.ssl.SSLHandshakeException:
java.security.cert.CertPathValidatorException: Trust anchor for
certification path not found.
Two points to be noted:
The HTTPS cert is valid. Easily opens without any warning on browser.
The above code works fine with HTTP links.
I actually need to know if there are any switches/options in the Android Volley framework by using which I'll successfully hit a HTTPS URL?
Warning: The following code should not be used in production because it is vulnerable to SSL attacks
Probably these codes below will be helpful for you:
1.Create a HttpsTrustManager class that implements X509TrustManager:
public class HttpsTrustManager implements X509TrustManager {
private static TrustManager[] trustManagers;
private static final X509Certificate[] _AcceptedIssuers = new X509Certificate[]{};
#Override
public void checkClientTrusted(
java.security.cert.X509Certificate[] x509Certificates, String s)
throws java.security.cert.CertificateException {
}
#Override
public void checkServerTrusted(
java.security.cert.X509Certificate[] x509Certificates, String s)
throws java.security.cert.CertificateException {
}
public boolean isClientTrusted(X509Certificate[] chain) {
return true;
}
public boolean isServerTrusted(X509Certificate[] chain) {
return true;
}
#Override
public X509Certificate[] getAcceptedIssuers() {
return _AcceptedIssuers;
}
public static void allowAllSSL() {
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String arg0, SSLSession arg1) {
return true;
}
});
SSLContext context = null;
if (trustManagers == null) {
trustManagers = new TrustManager[]{new HttpsTrustManager()};
}
try {
context = SSLContext.getInstance("TLS");
context.init(null, trustManagers, new SecureRandom());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
HttpsURLConnection.setDefaultSSLSocketFactory(context
.getSocketFactory());
}
}
2.Add HttpsTrustManager.allowAllSSL() before you make a https request:
HttpsTrustManager.allowAllSSL();
String tag_string_req = "string_req";
StringRequest strReq = new StringRequest(Request.Method.POST,
your_https_url, new Response.Listener<String>() {
#Override
public void onResponse(String response) {
Log.d(TAG, "response :"+response);
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
VolleyLog.d(TAG, "Error: " + error.getMessage());
}
}){
#Override
protected Map<String, String> getParams() {
Map<String, String> params = new HashMap<String, String>();
params.put("username", "max");
params.put("password", "123456");
return params;
}
};
AppController.getInstance().addToRequestQueue(strReq, tag_string_req);
you can add this class and execut it from onCreate method
new NukeSSLCerts().nuke();
it will make volley to Trust all SSL certificates.
So far the only answer talk about adding an untrusted certificate as the solution, but since your browser doesn't complain it usually means Volley can't find the intermediate certificate that does complete the full trusted chain.
It happened to me with LetsEncrypt certificates. Most browsers already have that intermediate certs so on browser everything looks fine, but Volley was apparently missing something.
The solution
Add the intermediate certificate to your webserver config. For Apache you can follow this reference:
https://access.redhat.com/solutions/43575
For LetsEncrypt it specifically is this file: /etc/letsencrypt/live/your.website.com/chain.pem
So besides your CertificateFile and KeyFile you should already have working you now have this third line:
SSLCertificateChainFile /etc/letsencrypt/live/your.website.com/chain.pem
Just adding that line, restarting apache and Volley doesn't complain anymore and you didn't introduce any security vulnerabilities!
If you are using volley and want to HTTPS request or SSL Certified service then you can choose this easiest way : -->
Step --> 1. keep .cer file into res/raw/ folder.
Step --> 2. Use this method and replace .cer file name with your .cer file and replace your host name also.
private SSLSocketFactory getSocketFactory() {
CertificateFactory cf = null;
try {
cf = CertificateFactory.getInstance("X.509");
InputStream caInput = getResources().openRawResource(R.raw.cert_name);
Certificate ca;
try {
ca = cf.generateCertificate(caInput);
Log.e("CERT", "ca=" + ((X509Certificate) ca).getSubjectDN());
} finally {
caInput.close();
}
String keyStoreType = KeyStore.getDefaultType();
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
keyStore.load(null, null);
keyStore.setCertificateEntry("ca", ca);
String tmfAlgorithm = TrustManagerFactory.getDefaultAlgorithm();
TrustManagerFactory tmf = TrustManagerFactory.getInstance(tmfAlgorithm);
tmf.init(keyStore);
HostnameVerifier hostnameVerifier = new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
Log.e("CipherUsed", session.getCipherSuite());
return hostname.compareTo("10.199.89.68")==0; //The Hostname of your server.
}
};
HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
SSLContext context = null;
context = SSLContext.getInstance("TLS");
context.init(null, tmf.getTrustManagers(), null);
HttpsURLConnection.setDefaultSSLSocketFactory(context.getSocketFactory());
SSLSocketFactory sf = context.getSocketFactory();
return sf;
} catch (CertificateException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
return null;
}
Step --> 3. Replace this line "RequestQueue queue = Volley.newRequestQueue(this);" with "RequestQueue queue = Volley.newRequestQueue(this, new HurlStack(null, getSocketFactory()));" in request of volley.
I couldn't open the link provided by #Ogre_BGR,but while browsing the net I found the actual implementation done in following smanikandan14 Github.Look upon his SSl-connection explanation to understand more about it.
This can happen for several reasons, including:
The CA that issued the server certificate was unknown
The server certificate wasn't signed by a CA, but was self signed
The server configuration is missing an intermediate CA
Official doc from android
Solution:
you can provide a certificate file within the request
For anyone who will come up against a problem like this and you use Letsencrypt for your SSL and node.js for webserver, try this. Assuming you have something like this. I fixed this by adding the line const chain = fs... Hope this helps
...
const app = express();
const privateKey = fs.readFileSync('ssl/privkey.pem', 'utf8');
const certificate = fs.readFileSync('ssl/cert.pem', 'utf8');
const chain = fs.readFileSync('ssl/chain.pem', 'utf8');
const credentials = {key: privateKey, cert: certificate, ca: chain};
...
var httpsServer = https.createServer(credentials, app);
I got the same problem when I add ssl to the domain, After 2 days gone, I found the solution the URL is getting wrong . I was using https://example.com but when I add ssl into domain the url will be change
https://www.example.com
And POST is working fine
got this error when i turned off proxy from cloudflare
check image here
the best solution for this problem is you can turn on proxy back and also add a full secure access on ssl certificate.
If anyone is using nginx and SSL certificates from letsencrypt, the solution is to simply use the certificate from file fullchain.pem instead of cert.pem:
ssl_certificate /.../fullchain.pem;
This file includes the concatenation of your certificate and the CA's.

Categories

Resources