Certificate pinning in Android
Asked Answered
M

0

6

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) ?

Monotony answered 9/8, 2014 at 20:54 Comment(8)
Your code looks like Option #1 from the blog post, but that is for a CA-less solution, not one with your own CA.Interdental
Why does the code work for my own CA then ?Monotony
My guess is that the way this works is that you are effectively pinning to the CA's root cert, and so any cert signed by this CA will validate, but certs signed by other CAs will not. My point was that the recipe is not for use with a CA, at least as far as Mr. Marlinspike's blog post covers. Hence, your statement that "This statement indicates that this tutorial is meant for the CA certificate I have" is false, insofar as Option #1 is not supposed to have a CA, but rather a self-signed cert for the server.Interdental
Pin the CA's or server's certificate with a custom TrustManager. Override the checkServerTrusted. For CA pinning, you're removing the CA Zoo and only using the one true CA. No other CA from the Zoo can claim to certify your site. For certificate pinning, your ensuring you get the expected server certificate. If you pin the server, you should choose the public key rather than the certificate. See OWASP's Certificate and Public Key Pinning.Demonstrate
"On the client side, you simply need to distribute the signing certificate with your app" - and that's the devil in the detail. To do that, you need a Trusted Distribution Channel to ensure your pinset is not tampered with.Demonstrate
@Demonstrate Is there any sample code on how to pin server using public key ?Monotony
@Demonstrate Can you elaborate your statement : need to ensure your pinset is not tampered with .. If I pin public key, I will generate pin and use in my app .. I think I don't followMonotony
@Monotony - what's your use case? Do you have a priori knowledge? If you have knowledge in advance, then you bundle the cert with your app. If you don't have advance knowledge, then you perform customary X509 checks and Trust-On-First-Use (TOFU). In subsequent connections, you pin against the TOFU. Gutmann talks a lot about it in Engineering Security.Demonstrate

© 2022 - 2024 — McMap. All rights reserved.