Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Certificate Pinning on Android with Robospice

I'm reading about certificate pinning on Android and I'm confused. I'm not using okhttp or retrofit so I have to do it manually. There is a tutorial here: https://www.owasp.org/index.php/Certificate_and_Public_Key_Pinning#Android where they are adding the certificate to list of trusted certificates. But there is also another tutorial when we're checking base64 of sha256 of the certificate installed on the server: https://medium.com/@appmattus/android-security-ssl-pinning-1db8acb6621e Which approach is the correct one? Why can't we just receive sha256 from the server in the header as browsers do and store it somewhere?

like image 289
falsetto Avatar asked Jun 19 '17 10:06

falsetto


1 Answers

I would recommend this
https://www.paypal-engineering.com/2015/10/14/key-pinning-in-mobile-applications/

Android Method

The simplest approach is to use a JSEE-based method as shown below. This is the recommended approach for Android. The method’s input arguments are an HTTPS connection and a set of valid pins for the targeted URL.


private boolean validatePinning(HttpsURLConnection conn, Set<String> validPins) {
    try {
        Certificate[] certs = conn.getServerCertificates();
        MessageDigest md = MessageDigest.getInstance("SHA-256");
        for (Certificate cert : certs) {
            X509Certificate x509Certificate = (X509Certificate) cert;
            byte[] key = x509Certificate.getPublicKey().getEncoded();
            md.update(key, 0, key.length);
            byte[] hashBytes = md.digest();
            StringBuffer hexHash = new StringBuffer();
            for (int i = 0; i < hashBytes.length; i++) {
                int k = 0xFF & hashBytes[i];
                String tmp = (k<16)? "0" : "";
                tmp += Integer.toHexString(0xFF & hashBytes[i]);
                hexHash.append(tmp);
            }
            if (validPins.contains(hexHash.toString())) {
                return true;
            }
        }
    } catch (Exception e) {
        e.printStackTrace();
        return false;
    }
    return false;
}

The pins are declared as strings. For instance:

Declaring Key Pins

private static final Set<String> PINS = new HashSet<String>(Arrays.asList(
        new String[]{
                "996b510ce2380da9c738...87cb13c9ec409941",
                "ba47e83b1ccf0939bb40d2...edf856ba892c06481a"}));

Leveraging the above method, here is an example showing how this can be put to use. The only relevant portion is highlighted below.

Example Using Key Pinning

protected String doInBackground(String... urls) {
    try {
        /** Test pinning given the target URL **/
        /** for now use pre-defined endpoint URL instead or urls[0] **/
        Log.i(LOG_TAG, "==> PinningTestTask launched.");
        String dest = defaultEndpoint;
        URL targetURL = new URL(dest);
        HttpsURLConnection targetConnection = (HttpsURLConnection) targetURL.openConnection();
        targetConnection.connect();
        if (validatePinning(targetConnection, PINS)) {
            final String updateText = "Key pinning succeded for: " + dest;
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    textView.setText(updateText);
                }
            });
        } else {
            final String updateText = "Key pinning failed for: " + dest;
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    textView.setText(updateText);
                }
            });
        }
    } catch (Exception e) {
        e.printStackTrace();
        final String updateText = "Key pinning failed for: " + dest + "\n" + e.toString();
        runOnUiThread(new Runnable() {
            @Override
            public void run() {
                textView.setText(updateText);
            }
        });
    }
    return null;
}
like image 104
Sri Kanth Avatar answered Sep 30 '22 05:09

Sri Kanth