简体   繁体   中英

Certificate pinning with okHttp

This question can be a duplicate of How can I pin a certificate with Square OKHTTP? But since it's not clear I'm asking again. I have to attach SSL certificate to my http client. I'm using retrofit version 2.2.0 and okHttp version 3.6.0

I have a certificate in .crt format. Currently I'm doing the certificate pinning as shown here . But I don't know its proper or not. Following is my code

       static void pinCertificate(Context context, OkHttpClient.Builder builder) {
            try {
                CertificateFactory cf = CertificateFactory.getInstance("X.509");
                InputStream cert = context.getResources().openRawResource(R.raw.certificate);
                Certificate ca;
                ca = cf.generateCertificate(cert);

                // creating a KeyStore containing our trusted CAs
                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);


                SSLContext sslContext = SSLContext.getInstance("TLS");
                sslContext.init(null, tmf.getTrustManagers(), null);
                builder.sslSocketFactory(sslContext.getSocketFactory());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

Is it the proper way to pin a .crt certificate with okHttp? How can we test if it is doing the handshake properly? If it is wrong can anyone show a sample code to pin the certificate properly? I saw some samples and documenst like this https://medium.com/@develodroid/android-ssl-pinning-using-okhttp-ca1239065616

but it is entirely different from what I have implemented. Nowhere they have used a crt file.

If someone could share a better explanation about certificate pinning and how it can be done in okHttp , it would be very helpful. Thanks in advance!!

See examples here https://square.github.io/okhttp/https/#certificate-pinning-kt-java

  private val client = OkHttpClient.Builder()
      .certificatePinner(
          CertificatePinner.Builder()
              .add("publicobject.com", "sha256/afwiKY3RxoMmLkuRW1l7QsPZTJPwDS2pdDROQjXw8ig=")
              .build())
      .build()

Reminder: Do not use certificate pinning without the blessing of your server's TLS administrator!

This is certificate pinning. It's the correct way. You can test it using fiddler or charles by installing https certificate in phone. If request is not success, then pinning is working fine. Test it by disabling ssl pinning as well. In that case request will be successful and you will be able to see request + data in fiddler or charles

You could also use public key pinning which will pin sha of public key inside certificate

I have implemented the following way

            InputStream cert = context.getResources().openRawResource(R.raw.certificate);            
            CertificateFactory cf=CertificateFactory.getInstance("X.509", "BC");
            InputStream caInput = new BufferedInputStream(cert);
            X509Certificate ca = (X509Certificate) cf.generateCertificate(caInput);
            caInput.close();
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            keyStore.load(null);
            keyStore.setCertificateEntry(ca.getSubjectX500Principal().getName(), ca);
            KeyManagerFactory kmf = KeyManagerFactory.getInstance("X509");
            kmf.init(keyStore, null);
            KeyManager[] keyManagers = kmf.getKeyManagers();
            TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
            tmf.init(keyStore);
            SSLContext context1 = SSLContext.getInstance("TLS");
            context1.init(keyManagers, tmf.getTrustManagers(), null);
            builder.sslSocketFactory(context1.getSocketFactory());

The way you are doing is the proper way. I did this too in the same way you are implementing. Its good to go with it. Happy Coding :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM