Pinning webview Certificate inside onReceivedClientCertRequest method - android

Is that possible to pinning webview Certificate inside onReceivedClientCertRequest method.
I want to implement something like :
#Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = MyHttpClient.context.getResources().openRawResource(R.raw.codeprojectssl); //name of your keystore file here
try {
// Initialize the keystore with the provided trusted certificates
// Provide the password of the keystore
trusted.load(in, "YourKeystorePassword".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER); // This can be changed to less stricter verifiers, according to need
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
inside this method that override from webview client :
#Override
#TargetApi(21)
public void onReceivedClientCertRequest (WebView view, ClientCertRequest request)
{
// By default pass to WebViewClient
super.onReceivedClientCertRequest(view, request);
}
is that possible, and is there a good example, because I can't find on google ?

Related

Importing certificate into a keystore on Android

I have a question about keystore.
Do android have a build in keystore?
If yes, where is the keystore?
Can I import my certificate into the keystore?
If yes, how can I do it manually and programmatically?
Please help, I have struggled with the SSLHandShakeException for a week.
I have used the keytool to generate a new keystore.bks and inserted the my certificate into it but I didn't know how can I use it for my android application.
I also tried the code that I have found online.
In MyHttpsClient.java
public class MyHttpsClient extends DefaultHttpClient{
final Context context;
public MyHttpsClient(Context context) {
System.out.println("context client http");
this.context = context;
}
#Override
protected ClientConnectionManager createClientConnectionManager(){
SchemeRegistry registry = new SchemeRegistry();
System.out.println("schema");
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", newSslSocketFactory(), 8080));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory(){
try{
KeyStore trusted = KeyStore.getInstance("BKS");
System.out.println("context client getInstance..");
InputStream in = context.getResources().openRawResource(R.raw.server);
System.out.println("context client input" + in);
try{
System.out.println("try");
trusted.load(in, "changeit".toCharArray());
}finally{
in.close();
}
System.out.println("finally");
SSLSocketFactory sf = new SSLSocketFactory(trusted);
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
}catch(Exception e){
throw new AssertionError(e);
}
}
}
In my Main.java
DefaultHttpClient client = new MyHttpsClient(getApplicationContext());
I have the code above in the onCreate() of my Main.java, but I have no idea why it doesn't go into my #Override function in MyHttpsClient.java
Can I read the original android emulator keystore and put the certificate into the keystore?

How to Handle SSL certification validation in proper way?

Hello my application is live and it is using "https" protocol. The Google Play Team throws warning as below.
"Your app(s) listed at the end of this email use an unsafe
implementation of the interface X509TrustManager. Specifically, the
implementation ignores all SSL certificate validation errors when
establishing an HTTPS connection to a remote host, thereby making your
app vulnerable to man-in-the-middle attacks. An attacker could read
transmitted data (such as login credentials) and even change the data
transmitted on the HTTPS connection. If you have more than 20 affected
apps in your account, please check the Developer Console for a full
list.
To properly handle SSL certificate validation, change your code in the
checkServerTrusted method of your custom X509TrustManager interface to
raise either CertificateException or IllegalArgumentException whenever
the certificate presented by the server does not meet your
expectations. Google Play will block publishing of any new apps or
updates containing the unsafe implementation of the interface
X509TrustManager."
In my project I am using custom http client to handle HTTPS instead default httpClient. My code is as below.
public static HttpClient getNewHttpClient() {
try
{
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
MySSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
}
catch (Exception e)
{
return new DefaultHttpClient();
}
}
public static class MySSLSocketFactory extends SSLSocketFactory {
SSLContext sslContext = SSLContext.getInstance("TLS");
public MySSLSocketFactory(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException {
super(truststore);
TrustManager tm = new X509TrustManager() {
public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
}
public X509Certificate[] getAcceptedIssuers() {
return null;
}
};
sslContext.init(null, new TrustManager[] { tm }, null);
}
#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();
}
}
How to overcome with this problem?
Hoping for favorable answers.
Now that you have posted the code concerned, it is difficult to see what part of the quoted message you don't understand.
The fix is simply to remove the TrustManager part of the code altogether, root and branch, and use the default one, and then deal with whatever problems may then arise in the proper way, by adjusting the contents of the truststore also as to trust all the certificates you need to trust that aren't already trusted by default. If any, which there shouldn't be.
Why do you need custom SSLSocketFactory. You can use DefaultHttpClient and that will handle all https by default. Just for your info, that HttpClient is deprecated and use HttpURLConnection.

No peer certificate error on android 2.3 devices but working fine on android 4+

I have created the bks file for my server's certificate. This was added in the project's sources in raw folder
I've created my https client as follows:
public class MyHttpsClient extends DefaultHttpClient {
final Context context;
public MyHttpsClient(Context context) {
this.context = context;
}
#Override
protected ClientConnectionManager createClientConnectionManager() {
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
// Register for port 443 our SSLSocketFactory with our keystore
// to the ConnectionManager
registry.register(new Scheme("https", newSslSocketFactory(), 443));
return new SingleClientConnManager(getParams(), registry);
}
private SSLSocketFactory newSslSocketFactory() {
try {
// Get an instance of the Bouncy Castle KeyStore format
KeyStore trusted = KeyStore.getInstance("BKS");
// Get the raw resource, which contains the keystore with
// your trusted certificates (root and any intermediate certs)
InputStream in = context.getResources().openRawResource(R.raw.mykeystore);
try {
// Initialize the keystore with the provided trusted certificates
// Also provide the password of the keystore
trusted.load(in, "testpassword".toCharArray());
} finally {
in.close();
}
// Pass the keystore to the SSLSocketFactory. The factory is responsible
// for the verification of the server certificate.
SSLSocketFactory sf = new SSLSocketFactory(trusted);
// Hostname verification from certificate
// http://hc.apache.org/httpcomponents-client-ga/tutorial/html/connmgmt.html#d4e506
sf.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
return sf;
} catch (Exception e) {
throw new AssertionError(e);
}
}
}
Then I use it like:
DefaultHttpClient httpClient = new MyHttpsClient(context);
HttpConnectionParams.setConnectionTimeout(httpClient.getParams(), 30000);
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost(url);
httpPost.setHeader("Accept", "application/json");
httpPost.setHeader("Content-type", "application/json");
httpPost.setEntity(new StringEntity(jsonString));
response = httpClient.execute(httpPost, localContext);
HttpEntity entity = response.getEntity();
httpresponse = getResponse(entity);
Now here comes the funny part. This works just fine on android 4+ both real devices and emulator. THIS fails on android 2.3 with
javax.net.ssl.SSLPeerUnverifiedException: No peer certificate
How can I make it work on android 2.3 without the known "trust all certificates" way ?
A few days age i solved same problem. The solution consisted in the following. I take all certificates installed on device(in my case it was samsung galaxy II) and go to the server side developer, who manage certificate chain installed on server. He analyzes ssl chain and detected that in chain there is one certificate (Thawte 2006) and other certificate (Thawte 2010). He removed oldest certificate, which issued in 2006, and ssl verification on android 2.x become working. I suggest you, before trying to get work local keystore, research your server side ssl chain and check that this chain doesn't have unnecessary certificates, because android 2.x devices cannot ignore not necessary certificates, but other platforms 3.x 4x and ios, windows phone can do it, i mean ignore "trash" in ssl certificate chain.

Certificate pinning in Android

I am trying to learn how to do certificate pinning in an Android application. I found the tutorial here. I wanted to clarify I doubt I have based on my testing this code.
I used the code as follows :
public class CertificatePinning {
static SSLSocketFactory constructSSLSocketFactory(Context context) {
SSLSocketFactory sslSocketFactory = null;
try {
AssetManager assetManager = context.getAssets();
InputStream keyStoreInputStream = assetManager.open("myapp.store");
KeyStore trustStore = KeyStore.getInstance("BKS");
trustStore.load(keyStoreInputStream, "somepass".toCharArray());
sslSocketFactory = new SSLSocketFactory(trustStore);
sslSocketFactory.setHostnameVerifier(SSLSocketFactory.STRICT_HOSTNAME_VERIFIER);
}
catch(Exception e){
Log.d("Exception", e.getLocalizedMessage());
}
return sslSocketFactory;
}
public static HttpClient getNewHttpClient(Context context) {
DefaultHttpClient httpClient = null;
try {
SSLSocketFactory sslSocketFactory = constructSSLSocketFactory(context);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sslSocketFactory, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
httpClient = new DefaultHttpClient(ccm, params);
} catch (Exception e) {
Log.d("Exception", e.getLocalizedMessage() );
return null;
}
return httpClient;
}
}
Quoting a statement from that tutorial :
On the client side, you simply need to distribute the signing certificate
with your app and validate against it.
On my web server, I have my own CA, which I created using open SSL, and used to sign certificates for different domain names that are used with my app.
This statement indicates that this tutorial is meant for the CA certificate I have. I tested the code using ca.pem (from my CA's crt file) and it works fine.
But I also tested the same code with a certificate I signed with that CA, e.g. server.pem ( from the signed server.crt), and still it works.
Did I do something wrong, or is this code meant for pinning either :
1) a CA certificate (covering all certificates signed by that CA) or
2) a particular certificate (signed by some CA) ?

SSL connection in android

I am in middle of developing an app in android, which requires me sslhandshake with server, using KSOAP2 libraries.
I am able to achieve the same on http sites, but fails on HTTPS sites,saying "could not validate certificate".
Can anybody help out
Please note that at least prior to 2.3 Android versions don't have the root CA for the RapidSSL CA among others.
You can check the issuer of a problematic certificate with sites such as http://www.digicert.com/help/
Another quick check is to try to load a HTTPs page in the stock browser and see if it complains about the certificate.
If this does not match your situation then ignore this answer.
If you have a certificate signed by this CA you must either
Handle it explicitly in your app by doing something like Danieles answer, but actually also comparing the certificate to a stored one for RapidSSL (or whichever you use).
Add an intermediate certificate to the chain at the web server in question to make the RapidSSL certificate certified by GeoTrust.
Check out
http://code.google.com/p/android/issues/detail?id=10807
https://knowledge.rapidssl.com/support/ssl-certificate-support/index?page=content&id=AR1549
It may be because the site you are trying to access may not have CA. It only may only have self-signed certificate. That is a issue you will get when you dealing with self-signed certificate.
Try these links and show us what you have implemented already
http://developer.android.com/reference/javax/net/ssl/HttpsURLConnection.html
http://developer.android.com/reference/org/apache/http/conn/ssl/SSLSocketFactory.html
Can this code be of help?
https://github.com/mixare/mixare/blob/master/src/org/mixare/MixContext.java
HttpsURLConnection.setDefaultHostnameVerifier(new HostnameVerifier(){
public boolean verify(String hostname, SSLSession session) {
return true;
}});
SSLContext context = SSLContext.getInstance("TLS");
context.init(null, new X509TrustManager[]{new X509TrustManager(){
public void checkClientTrusted(X509Certificate[] chain,
String authType) throws CertificateException {}
public void checkServerTrusted(X509Certificate[] chain,
String authType) throws CertificateException {}
public X509Certificate[] getAcceptedIssuers() {
return new X509Certificate[0];
}}}, new SecureRandom());
HttpsURLConnection.setDefaultSSLSocketFactory(
context.getSocketFactory());
This code is used in mixare.org to accept self-signed certificates.
Please be aware that you are not safe from MITM attacks when using this approach.
HTH,
Daniele
You can Use SelfSignedCertificate. Just use this method as your HTTPClient:
public static HttpClient getNewHttpClient() {
try {
KeyStore trustStore = KeyStore.getInstance(KeyStore.getDefaultType());
trustStore.load(null, null);
SSLSocketFactory sf = new MySSLSocketFactory(trustStore);
sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
HttpParams params = new BasicHttpParams();
HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
HttpProtocolParams.setContentCharset(params, HTTP.UTF_8);
SchemeRegistry registry = new SchemeRegistry();
registry.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
registry.register(new Scheme("https", sf, 443));
ClientConnectionManager ccm = new ThreadSafeClientConnManager(params, registry);
return new DefaultHttpClient(ccm, params);
} catch (Exception e) {
return new DefaultHttpClient();
}
}

Categories

Resources