Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add multiple SSL certificate pinning to Android KeyStore doesn't work. (from Resource file)

I want to add multiple SSL certificates from a ressource file to the Android KeyStore as follow:

if (sslContext==null) {
        // loading CA from an InputStream
        InputStream is = AVApplication.getContext().getResources().openRawResource(R.raw.wildcard);
        String certificates = Converter.convertStreamToString(is);
        String certificateArray[] = certificates.split("-----BEGIN CERTIFICATE-----");

        for (int i = 1; i < certificateArray.length; i++) {
            certificateArray[i] = "-----BEGIN CERTIFICATE-----" + certificateArray[i];
            //LogAV.d("cert:" + certificateArray[i]);

            // generate input stream for certificate factory
            InputStream stream = IOUtils.toInputStream(certificateArray[i]);

            // CertificateFactory
            CertificateFactory cf = CertificateFactory.getInstance("X.509");
            // certificate
            Certificate ca;
            try {
                ca = cf.generateCertificate(stream);
            } finally {
                is.close();
            }

            // creating a KeyStore containing our trusted CAs
            KeyStore ks = KeyStore.getInstance("BKS");
            ks.load(null, null);
            ks.setCertificateEntry("av-ca" + i, ca);

            // TrustManagerFactory
            String algorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
            // Create a TrustManager that trusts the CAs in our KeyStore
            tmf.init(ks);

            // Create a SSLContext with the certificate that uses tmf (TrustManager)
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
        }

    }

    return sslContext;

Only the last certificate of the file works! It seems the certificate overwrites the other one.

File looks like:

-----BEGIN CERTIFICATE-----
    cert 
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
    cert 
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
    cert 
-----END CERTIFICATE-----

I hope somebody can help me! :)

like image 846
Manuel Schmitzberger Avatar asked Feb 16 '16 11:02

Manuel Schmitzberger


People also ask

Can you have multiple SSL certificates one domain?

You can install multiple SSL certificates on a domain, but first a word of caution. A lot of people want to know whether you can install multiple SSL certificates on a single domain. The answer is yes.

Is SSL pinning applicable to Android?

ssl package and you can use it to implement Android Certificate Pinning. Keep reading for a step-by-step tutorial on how to implement pinning using this component. Load KeyStore with the Certificate file from resources (as InputStream). Get TrustManagerFactory and init it with KeyStore.

Why is my SSL certificate not working on mobile?

This is the most common reason behind SSL certificate errors. If there's a mismatch between the clock on your device and the clock of web server that you're trying to access then SSL certificate of website won't be verified. As a result, you'll get an SSL error.

Why do we pin a certificate?

What Are the Benefits? Certificate pinning offers enhanced control for organizations that wish to custom-design certificate-based authentication and encryption security directly into their online applications and mobile applications.


1 Answers

Thx to @Dan Getz, now it works.

1. Solution with SSL context & Self signed Certificate:

public static SSLContext getSSLContext() throws Exception {
        if (sslContext==null) {
            // loading CA from an InputStream
            InputStream is = AVApplication.getContext().getResources().openRawResource(R.raw.certificates);
            String certificates = Converter.convertStreamToString(is);
            String certificateArray[] = certificates.split("-----BEGIN CERTIFICATE-----");

            // creating a KeyStore containing our trusted CAs
            KeyStore ks = KeyStore.getInstance("BKS");
            ks.load(null, null);
            for (int i = 1; i < certificateArray.length; i++) {
                certificateArray[i] = "-----BEGIN CERTIFICATE-----" + certificateArray[i];
                //LogAV.d("cert:" + certificateArray[i]);

                // generate input stream for certificate factory
                InputStream stream = IOUtils.toInputStream(certificateArray[i]);

                // CertificateFactory
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                // certificate
                Certificate ca;
                try {
                    ca = cf.generateCertificate(stream);
                } finally {
                    is.close();
                }

                ks.setCertificateEntry("av-ca" + i, ca);
            }
            // TrustManagerFactory
            String algorithm = TrustManagerFactory.getDefaultAlgorithm();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(algorithm);
            // Create a TrustManager that trusts the CAs in our KeyStore
            tmf.init(ks);

            // Create a SSLContext with the certificate that uses tmf (TrustManager)
            sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, tmf.getTrustManagers(), new SecureRandom());
        }

        return sslContext;
    }

Then using the SSL context:

client = okHttpClient.newBuilder()
         .sslSocketFactory(getSslContext(context).getSocketFactory())
         .build();

2. Solution with Pinning a not root certificate with OkHttp via fingerprints:

Pinning a non root CA, I'm using the CertificatePinner from OkHttp (! this does not work for self-signed certificate - root CAs):

CertificatePinner = new CertificatePinner.Builder()
            .add(new URL(url).getHost(), "sha256/<certificate1 fingerprint [base64]>")
            .add(new URL(url).getHost(), "sha256/<certificate2 fingerprint [base64]>")
            .build();
OkHttpClient client;
    client = okHttpClient.newBuilder()
        .certificatePinner(certificatePinner)
        .build();
like image 161
Manuel Schmitzberger Avatar answered Sep 17 '22 18:09

Manuel Schmitzberger