Skip to main content
Version: 7.0.1

SSL Pinning

The Secure Sockets Layer (SSL)—now technically known as Transport Layer Security (TLS)—is a common building block for encrypted communications between clients and servers. It's possible that an application might use SSL incorrectly such that malicious entities may be able to intercept an app's data over the network.

SSL pinning also known as Public Key Pinning is an attempt to solve these issues, ensuring that the certificate chain used is the one your app expects by checking a particular public key or certificate appears in the chain.

Implementing SSL pinning on Android

Add a Network Security Configuration file

The Network Security Configuration feature uses an XML file where you specify the settings for your app. You must include an entry in the manifest of your app to point to this file. The following code excerpt from a manifest demonstrates how to create this entry:


<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
<application android:networkSecurityConfig="@xml/network_security_config"
... >
...
</application>
</manifest>

Pin certificates

Normally, an app trusts all pre-installed CAs. If any of these CAs were to issue a fraudulent certificate, the app would be at risk from a man-in-the-middle attack. Some apps choose to limit the set of certificates they accept by either limiting the set of CAs they trust or by certificate pinning.

Certificate pinning is done by providing a set of certificates by hash of the public key (SubjectPublicKeyInfo of the X.509 certificate). A certificate chain is then valid only if the certificate chain contains at least one of the pinned public keys.

Note that, when using certificate pinning, you should always include a backup key so that if you are forced to switch to new keys or change CAs (when pinning to a CA certificate or an intermediate of that CA), your app's connectivity is unaffected. Otherwise, you must push out an update to the app to restore connectivity.

Additionally, it is possible to set an expiration time for pins after which pinning is not performed. This helps prevent connectivity issues in apps which have not been updated. However, setting an expiration time on pins may enable pinning bypass.

config/Android/network_security_config.xml:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<domain-config>
<domain includeSubdomains="true">example.com</domain>
<pin-set>
<pin digest="SHA-256">7HIpactkIAq2Y49orFOOQKurWxmmSFZhBCoQYcRhJ3Y=</pin>
<!-- backup pin -->
<pin digest="SHA-256">fwza0LRMXouZHRC8Ei+4PyuldPDcf3UKgO/04cDM1oE=</pin>
</pin-set>
</domain-config>
</network-security-config>

Syntax:

<pin-set>: A set of public key pins. For a secure connection to be trusted, one of the public keys in the chain of trust must be in the set of pins. See <pin> for the format of pins.

<pin>: containsdigest attribute. The digest algorithm used to generate the pin. Currently, only "SHA-256" is supported.

<pin digest=["SHA-256"]>base64 encoded digest of X.509
SubjectPublicKeyInfo (SPKI)</pin>

For more detail, please visit here.

Retrieving your public keys

To implement the pinning examples shown here you need to know your certificates SPKI data.

Given a domain name, the code below prints out the public keys in the chain as a SHA-256 hash using base 64 encoding.

openssl s_client -connect example.com:443 | openssl x509 -pubkey -noout | openssl rsa -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64

Implementing SSL Pinning on iOS

To get SSL Pinning on iOS, you should import the .der file containing the certificate. This file is normally provided by the other sources, but in case you need to create for your own, you need to use this command (Works on Mac). Example with httpbin.org:

openssl s_client -connect httpbin.org:443 </dev/null | openssl x509 -outform DER -out httpbin.org.der

After you've done with extracting the .der file, you should add the key to your assets file. You can get more information on how to add files to your assets, please refer to the document below:

Project Architecture

Usage of SSL Pinning

Depending on your network requests, you might be following one of the methods provided below to make http calls:

  • Webview
  • Using Http
  • Using Service-call utility
  • Using Image.loadFromUrl method (ssl pinning isn't supported in this case)

If you are using 3rd party networking tools like Axios, they have their own method of SSL pinning and Smartface does not guarantee that it will play nicely with the native methods.

WebView

For iOS, you need to add sslPinning property to your webview.

this.myWebView = new WebView({
ios: {
sslPinning: [
{
host: "smartface.io",
certificates: ["assets://yourcertificate.der"],
validateCertificateChain: true,
validateHost: true,
}
]
}
});

When the certificate is invalid, webView will throw an error and onError event will be triggered.

Http

For iOS, you need to add sslPinning property to your http call

const myHttp = new Http({
ios: {
sslPinning: [
{
host: "smartface.io",
certificates: [],
validateCertificateChain: false,
validateHost: false,
}
]
}
});

Service Call Utility

If you are using the service-call utility, same syntax is still applied. Simply use it like shown below:

export const sc = new ServiceCall({
baseUrl: "http://api.myBaseUrl.com",
logEnabled: true,
headers: {
apiVersion: "1.0",
},
sslPinning: [
{
host: "smartface.io",
certificates: [],
validateCertificateChain: false,
validateHost: false,
},
],
});
info

Same syntax applies for service-call-offline utility which supports offline connection and queue up the calls.

More information can be found at the utility documentation:

https://smartface.github.io/sf-extension-utils/modules/service_call.html