Skip to main content

Certificate pinning

Compares a certificate stored in the mobile app as being the same certificate presented by the web server that provides the HTTPS connection.

Please note: CertificatePinner can not be used to pin self-signed certificate if such certificate is not accepted by TrustManager.

This will pin the connections for a host to the public key of a certificate.

NetworkHandler.sharedInstance().setCertificatePinner(new CertificatePinner.Builder()
        .add("yourhost", "sha256/public_key_of_certificate")

Asterisk * is only permitted in the left-most domain name label and must be the only character in that label, e.g. * is permitted, while * is not.

Self-signed certificates

This section applies to SSL settings for connections only to IBM Security Access Manager appliances. It will not have any effect on connections to IBM Security Verify.

If you use self-signed certificates, you additionally need to customize SSLContext, HostnameVerifier and TrustManager.

Downloading the certificate

Working with a development server, the following is the easiest way to download a certificate chain:

# for DER:
openssl s_client -connect <host>:<port> -showcerts 2>/dev/null </dev/null | openssl x509 -inform pem -outform der -out <certificate-name>.der

# for PEM:
openssl s_client -connect <host>:<port> -showcerts 2>/dev/null </dev/null | openssl x509 -inform pem -outform pem -out <certificate-name>.pem

Customize SSL settings

This sample overrides the SSL settings, so that the certificate provided by the server is accepted for this connection.

private final String certificatePath = "my-server-certificate.crt";
private final String expectedHostname = "";

TrustManager tm = new X509TrustManager() {
    public void checkClientTrusted(X509Certificate[] chain, String authType) {

    public void checkServerTrusted(X509Certificate[] chain, String authType) {

    public X509Certificate[] getAcceptedIssuers() {
        return new[]{};

HostnameVerifier makeHostnameVerifier(String expectedHostname) {
    return new HostnameVerifier() {
        public boolean verify(String hostname, SSLSession session) {
            return hostname.equalsIgnoreCase(expectedHostname);

SSLContext makeSslContext(String filename) {
    InputStream caInput = null;
    SSLContext context = null;
    try {
        CertificateFactory cf = CertificateFactory.getInstance("X.509");
        InputStream in = getClass().getClassLoader().getResourceAsStream(filename);
        caInput = new BufferedInputStream(in);
        final Certificate ca;

        ca = cf.generateCertificate(caInput);
        Log.d("Certificate pinning", "makeSslContext: ca=" + ((X509Certificate) ca).getSubjectDN());

        KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
        keyStore.load(null, null);
        keyStore.setCertificateEntry("our trusted CA", ca);

        TrustManager customTrustManager = new X509TrustManager() {
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                throw new CertificateException("This doesn't need to ever succeed");

            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                byte[] found = chain[0].getEncoded();
                byte[] wanted = ca.getEncoded();
                if (!Arrays.equals(found, wanted)) {
                    throw new CertificateException("Presented certificate didn't match pinned certificate");

            public X509Certificate[] getAcceptedIssuers() {
                return new X509Certificate[0];

        context = SSLContext.getInstance("TLS");
        context.init(null, new TrustManager[] {customTrustManager}, null);

    } catch (CertificateException | KeyStoreException | NoSuchAlgorithmException | IOException | KeyManagementException e) {

    } finally {
        if (caInput != null) try { caInput.close(); }
        catch (IOException e) {
    return context;

NetworkHandler.sharedInstance.setOnPremiseSslParameter(makeSslContext(certificatePath), tm, makeHostnameVerifier(expectedHostname));

Allow all connections

The SDK provides implementations that basically turns off SSL checks. Be careful if you use them!