Your Questions and Doubts
Should the same public certificate verify with all certificates in the chain?
No, because each certificate in the chain (root, intermediate and leaf certificate)) was signed with a different private/public key pair.
One of the items in the chain verifies and the other doesn't (which throws an Exception). I guess I can't get a grasp of how certificate chains work.
That's because your certificate is the leaf one, thus you can only verify your public key against it, not against the root and intermediate certificate(s).
A Code Approach
I subclass SSLSocketFactory and override the checkServerTrusted() method.
If you really want to code it yourself I would suggest you to use instead the built-in OkHttp Ceritficate Pinner, that you can build like this:
import okhttp3.CertificatePinner;
public class OkHttpPinnerService {
// true if the Approov SDK initialized okay
private boolean initialized;
// cached OkHttpClient to use or null if not set
private OkHttpClient okHttpClient;
public synchronized OkHttpClient getOkHttpClient() {
if (okHttpClient == null) {
// build a new OkHttpClient on demand
if (initialized) {
// build the pinning configuration
CertificatePinner.Builder pinBuilder = new CertificatePinner.Builder();
Map<String, List<String>> pins = YourConfig.getPins("public-key-sha256");
for (Map.Entry<String, List<String>> entry : pins.entrySet()) {
for (String pin : entry.getValue())
pinBuilder = pinBuilder.add(entry.getKey(), "sha256/" + pin);
}
// build the OkHttpClient with the correct pins preset and ApproovTokenInterceptor
Log.i(TAG, "Building new Approov OkHttpClient");
okHttpClient = okHttpBuilder.certificatePinner(pinBuilder.build()).build();
} else {
// if the Approov SDK could not be initialized then we can't pin or add Approov tokens
Log.e(TAG, "Cannot build Approov OkHttpClient due to initialization failure");
okHttpClient = okHttpBuilder.build();
}
}
return okHttpClient;
}
}
The code was not tested for syntax errors or logical correctness. I just copied it from this repo and slightly adapted it.
A Codeless Approach
Since Android API 24 it is possible to implement certificate pinning to the public key hash via the built-in security config file, that doesn't require any code to be written, just a properly configured network_security_config.xml file added to your project.
To avoid mistakes while building the network_security_config.xml file I recommend you to use the Mobile Certificate Pinning Generator to extract the live pin being used by the domain you want to pin against and to build for you the correct configuration. For example:
![From to add the domains to pin]()
![Android network security configuration]()
Now just copy paste the generated configuration the network_security_config.xml file in your project and add this same file to the AndroifManifest.xml. Just follow the instructions on the page.