ForgeRock SDKs

Enable SSL pinning

The ForgeRock SDKs support SSL pinning, sometimes referred to as certificate pinning. SSL pinning is the security practice of validating the certificates presented by the server against known values.

When the SDK attempts to make an HTTPS connection to the authorization server (AM), it first verifies that a hash of the server’s public key (obtained from the server’s SSL certificate) matches a set of hashes defined within your app. This SSL pinning reduces the chance of a man-in-the-middle (MITM) attack, improving the security of your app.

If the hash does not match, your app does not connect to the authorization server, and an error is returned instead. Note that if your public key changes, you will need to rebuild and re-release your app with the new hash included.

Get a hash of AM’s public key

To enable SSL pinning you need a hash of your AM authorization server’s public key. You can use the openssl tool to extract this from your server’s SSL certificate and create the hash value.

In the following command, replace <tenant-env-fqdn> with the fully-qualified domain name of your AM server, for example, my-company.forgeblocks.com:

echo | openssl s_client -servername <tenant-env-fqdn> -connect <tenant-env-fqdn>:443 | openssl x509 -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

The command outputs a hash of the public key extracted from the certificate:

S4kZuhQQ1DPcXBSWFQXD0gG+UW7usdbVx6roNWpRl65I=

Proceed to configure SSL pinning to learn how to configure this value in the SDK.

Configure SSL pinning in Android

To enable SSL pinning in the ForgeRock SDK for Android, add the hash of the public keys for any AM authorization servers your application will contact to your app’s configuration.

Add the hashes to an array named forgerock_ssl_pinning_public_key_hashes in your strings.xml file:

<string-array name="forgerock_ssl_pinning_public_key_hashes">
   <item>S4kZuhQQ1DPcXBSWFQXD0gG+UW7usdbVx6roNWpRl65I=</item>
</string-array>

If the public key you use to obtain SSL certificates for the AM servers change, update the strings.xml file with the new hash and re-release your app.

You can also update this property programmatically by using dynamic configuration.

Override default implementation of SSL pinning for Android

You can override how the ForgeRock SDK for Android performs SSL pinning by registering your own implementation.

To override the default SSL pinning, you create your own implementation of checkServerTrusted():

try {
    final TrustManager myCustomTrustManager = new X509TrustManager() {
        @Override
        public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {}

        @Override
        public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) {
            // Provide custom SSL Pinning handling
        }

        @Override
        public java.security.cert.X509Certificate[] getAcceptedIssuers() {
            return new java.security.cert.X509Certificate[] {};
        }
    };
    SSLContext sslContext = SSLContext.getInstance("SSL");
    sslContext.init(null, new TrustManager[] { myCustomTrustManager }, new java.security.SecureRandom());
    Config.getInstance().reset();
    Config.getInstance().init(this, null);
    Config.getInstance().setBuildSteps(Collections.singletonList(builder1 -> {
        builder1.sslSocketFactory(sslContext.getSocketFactory(), (X509TrustManager) myCustomTrustManager);
        builder1.hostnameVerifier((s, sslSession) -> true);
    }));

} catch (NoSuchAlgorithmException | KeyManagementException e) {
    runOnUiThread(() -> content.setText(e.getMessage()));
}

Alternatively, you can use dynamic configuration to override the SDK’s SSL pinning functionality:

val myCustomTrustManager: TrustManager = object : X509TrustManager {
    override fun checkClientTrusted(chain: Array<X509Certificate>, authType: String) {}
    override fun checkServerTrusted(chain: Array<X509Certificate>, authType: String) {
        // Provide custom SSL Pinning handling
    }
    override fun getAcceptedIssuers(): Array<X509Certificate> {
        return arrayOf()
    }
}
val sslContext = SSLContext.getInstance("SSL")
sslContext.init(null, arrayOf(myCustomTrustManager), SecureRandom())

val option = FROptionsBuilder.build {
    server {
        forgerock_url = "https://custom.example.com"
        forgerock_realm = "prod"
    }
    sslPinning {
        buildSteps = listOf(object: BuildStep<OkHttpClient.Builder> {
            override fun build(builder1: OkHttpClient.Builder) {
                builder1.sslSocketFactory(
                    sslContext.socketFactory,
                    myCustomTrustManager as X509TrustManager
                )
                builder1.hostnameVerifier { s, sslSession -> true }
            }
        })
        forgerock_ssl_pinning_public_key_hashes = emptyList()
    }
}
Copyright © 2010-2022 ForgeRock, all rights reserved.