Security certificate in android studio + Volley

1

I am using the following code to generate a Singleton instance of the Volley class and incorporate a security certificate, the problem is that now I need to attach another certificate and I have no idea where to do it.

public class VolleySingleton {
private static VolleySingleton instance;
private RequestQueue request;
private static Context context;

private VolleySingleton(Context context) {
    VolleySingleton.context = context;
    request = getRequestQueue();
}

public static synchronized VolleySingleton getInstance(Context context) {
    if (instance == null) {
        instance = new VolleySingleton(context);
    }
    return instance;
}

public RequestQueue getRequestQueue() {
    if (request == null) {
        request = Volley.newRequestQueue(context.getApplicationContext(), new HurlStack(null, getSocketFactory()));
    }
    return request;
}

public <T> void addToRequestQueue(Request<T> req) {
    getRequestQueue().add(req);
}

private SSLSocketFactory getSocketFactory() {

    CertificateFactory cf = null;
    try {

        cf = CertificateFactory.getInstance("X.509");
        InputStream caInput = context.getResources().openRawResource(R.raw.certcidi);
        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("mobilecidi.cba.gov.ar") == 0; //The Hostname of your server.
            }
        };

        HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
        SSLContext 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;
}

}

Could someone guide me?

    
asked by DavidC 07.12.2018 в 13:39
source

2 answers

2

To add another certificate you need:

1) The X509 certificate in DER in res/raw (similar to the one that is already).

If you have the certificate in PEM format (It looks like text with --BEGIN CERTIFICATE-- and --END CERTIFICATE-- ) you have to convert it to format% der_co%.

One way to do it is with DER :

openssl x509 -outform der -in certificado2.pem -out certificado2.der

Note: certificate2.pem is the file with the certificate in PEM format

Then the file openssl must be added to the project in Android Studio in certificado2.der along with the other certificate to have there.

2) Create an instance of res/raw with that certificate.

In Certificate replicate the block that creates the instance:

    cf = CertificateFactory.getInstance("X.509");
    InputStream caInput = context.getResources().openRawResource(R.raw.certcidi);
    Certificate ca, ca2;
    try {
        ca = cf.generateCertificate(caInput);
        Log.e("CERT", "ca=" + ((X509Certificate) ca).getSubjectDN());
    } finally {
        caInput.close();
    }

    caInput = context.getResources().openRawResource(R.raw.certificado2);
    try {
        ca2 = cf.generateCertificate(caInput);
        Log.e("CERT", "ca2=" + ((X509Certificate) ca2).getSubjectDN());
    } finally {
        caInput.close();
    }

With this we have in getSocketFactory() the first certificate and in ca the second.

3) Save the Certificate instance in the KeyStore, along with the one that is already.

Also in ca2 :

    String keyStoreType = KeyStore.getDefaultType();
    KeyStore keyStore = KeyStore.getInstance(keyStoreType);
    keyStore.load(null, null);
    keyStore.setCertificateEntry("ca", ca);
    keyStore.setCertificateEntry("ca2", ca2);

4) Modify the getSocketFactory() to validate the name of the new server.

Here it is simply valid that the reported hostname matches either the perimero or the second server.    Maybe it can be improved in some way to distinguish if the connection is to one or the other server but I did not find a simple way to get the url within hostNameVerifier() .

HostnameVerifier hostnameVerifier = new HostnameVerifier() {
    @Override
    public boolean verify(String hostname, SSLSession session) {
        Log.e("CipherUsed", session.getCipherSuite());

        return (hostname.compareTo("mobilecidi.cba.gov.ar") == 0 || 
                hostname.compareTo("nombre.esperado.2do.server.en.certificado") == 0); //The Hostname   of your server.
        }
};
    
answered by 07.12.2018 / 15:49
source
0

I was able to solve it with Juan's letter.

I leave the complete code in case someone serves you

public class VolleySingleton {
private static VolleySingleton instance;
private RequestQueue request;
private static Context context;

private VolleySingleton(Context context) {
    VolleySingleton.context = context;
    request = getRequestQueue();
}

public static synchronized VolleySingleton getInstance(Context context) {
    if (instance == null) {
        instance = new VolleySingleton(context);
    }
    return instance;
}

public RequestQueue getRequestQueue() {
    if (request == null) {
        request = Volley.newRequestQueue(context.getApplicationContext(), new HurlStack(null, getSocketFactory()));
    }
    return request;
}

public <T> void addToRequestQueue(Request<T> req) {
    getRequestQueue().add(req);
}

private SSLSocketFactory getSocketFactory() {

    CertificateFactory cf = null;
    try {

        cf = CertificateFactory.getInstance("X.509");
        InputStream caInput = context.getResources().openRawResource(R.raw.certcidi);
        Certificate ca, ca2;
        try {
            ca = cf.generateCertificate(caInput);
            Log.e("CERT", "ca=" + ((X509Certificate) ca).getSubjectDN());
        } finally {
            caInput.close();
        }

        caInput = context.getResources().openRawResource(R.raw.certpaypertic);

        try {
            ca2 = cf.generateCertificate(caInput);
            Log.e("CERT", "ca2=" + ((X509Certificate) ca2).getSubjectDN());
        } finally {
            caInput.close();
        }

        String keyStoreType = KeyStore.getDefaultType();
        KeyStore keyStore = KeyStore.getInstance(keyStoreType);
        keyStore.load(null, null);
        keyStore.setCertificateEntry("ca", ca);
        keyStore.setCertificateEntry("ca2", ca2);

        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("mobilecidi.cba.gov.ar") == 0 ||
                        hostname.compareTo("a.paypertic.com") == 0);
            }
        };

        HttpsURLConnection.setDefaultHostnameVerifier(hostnameVerifier);
        SSLContext 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;
}

}

    
answered by 07.12.2018 в 17:11
JAVA - Netbeans - FOR Cycle ___ ___ erkimt Listview in Uneven c # ______ qstntxt ___

I am filling a listview from a select to the Oracle database. This is the code.

%pre%

What this result presents to me:

Now ... what I need is for it to look something like this: } }

It would be to group the orders with the same id.

The select to the database is a view that would be this:

%pre%     
______ azszpr220169 ___

Assuming that your query is ordered as you want, that is, the records are correct, what you should do would be something like this:

%pre%

What we are doing here is comparing the order with the previous one. If the order is different, we put all the data we want in the list .. If not, we leave those columns blank, and only fill the others.

This way you will achieve what you need. Notice that if the orders are different, I change the current order. And I start the first one in 0.

This is commonly known as control cuts.

    
___