May 29th, 2020 | By Karan Gandhi | 5 min read
Transport Layer Security (TLS) is a cryptographic protocol that is used to secure communications over the network. TLS was preceded by Secure Sockets Layer (SSL). Websites use TLS to secure communications between servers and web browsers.
The common flow in a TLS connection is as follows:
A client initiates a connection to the server;
The server responds with a certificate containing its public key;
The client verifies the certificate with preinstalled Certified Authority (CA) certificates on the computer;
On success, the client creates a new secret key which is encrypted using Server's Public key;
The server decrypts the new key with its private key;
All further communications are carried using this secret key.
CAs play a key role in securing the connections. They issue digital certificates that certify ownership of public keys, usually X.509.
Asymmetric Cryptography is a system that uses a pair of public and private keys to secure a system. A user can distribute his public key which in turn can be used by others to sign a message. A user can verify the authenticity of the message using his private key. A digital certificate is an electronic document that certifies ownership of a public key. If the signature is valid and the issuer is trusted, then that key can be used to communicate securely. In our context, the Certificate Authority is the issuer. Let's take a look at the different types of certificates.
Root Certificates: this is a certificate that identifies a Certificate Authority. These certificates are self-signed. Usually CAs issue certificates in a tree format. Root certificates are used to sign an intermediate certificate and establish a root chain. Intermediate certificates inherit the trustworthiness of the root chain. Major software companies like Microsoft, Apple, Mozilla, Google, Oracle have their Root Programs to store root certificates. Root stores are certificates installed in operating systems.
Intermediate certificates: CAs don't issue server certificates directly from a root certificate. They usually sign an intermediate certificate with its private key. As mentioned earlier, the certificate inherits the trustworthiness of a parent. This process can be repeated multiple times to form a certificate chain. The end-user certificate or Leaf certificate is usually signed by an intermediate certificate. There is a huge risk involved in signing with root - it's easier to revoke an intermediate certificate.
Leaf Certificate: this refers to certificates that cannot be used to sign other certificates. SSL/TLS server certificates are usually leaf certificates.
Self Signed Certificates: lastly, if a certificate is not signed by a CA, then it's a self-signed certificate. Self-signed certificates can be created using tools like Apples' Keychain, OpenSSL, and Java's Keytool. Self-signed certificates are useful for testing. However, they are susceptible to Man-in-the-Middle (MiTM) attacks. It's advised to avoid self-signed certificates in production.
As mentioned earlier, a CA doesn't sign a leaf certificate with its root. A complex chain of intermediate certificates is established, with each intermediate certificate inheriting the trustworthiness of its parent.
Usually, while connecting to a secure server, the client downloads the server certificate. Unless the certificate is self-signed, the certificate used to sign a leaf certificate is downloaded. If the intermediate certificate is not root, then the process is repeated. If the final certificate is a root certificate and it is verified, the entire chain of certificates is trusted and hence the connection is trusted. If the root is not verified or if the last certificate is not a root certificate, then the chain is untrusted.
HTTPS traffic can potentially be intercepted by installing malicious CA certificates in a device. Tools like OWASP ZAP, Burp, and mitmproxy auto-generate CAs to intercept traffic from the browser. Usually, malicious actors use social engineering to install rogue CAs on devices. Unlike home computers, it's relatively easier to install certificates on mobiles. Commonly, WiFi hotspots can be used to install such rogue CAs.
We can use certificate pinning to add an extra layer of defense. Certificate pinning is a technique with which we can directly associate the host/app to a certificate or its public key instead of accepting any certificate signed by a trusted CA. By revoking trust from CA, we are reducing the attack surface. As such, even if an attacker manages to install a rogue CA on a device, he won't be able to intercept traffic easily. The best practice is to pin the server's leaf certificate. However, a developer can choose to pin an intermediate certificate to increase compatibility. This will allow us to change the server's leaf certificate periodically - but it also increases the attack surface.
We can implement pinning in two ways.
First, we can directly pin the certificate by bundling the certificate in our apps. However, once the certificate expires, a transition plan will have to be implemented beforehand. Once the certificate expires, older apps will throw errors.
Second, we can pin the Public Key of the certificate. By pinning a public key, we won't have to worry about the certificate expiring as long as the public key remains the same. We can pin multiple certificates - such an arrangement is known as a pinset.
Let's take a look at commonly used plugins in React Native and Ionic.
In a previous article, we have mentioned plugins that can be used for certificate pinning. We will list them here again.
react-native-ssl-pinning: This plugin uses OkHttp3 on Android and AFNetworking on iOS to provide SSL pinning and cookie handling. It supports both Certificate and Public Key Pinning. We will be using fetch from the library to consume APIs. This library uses promises and supports multi-part form data. It has support for React Native 0.60 and above.
react-native-pinch: React Native Pinch is used to pin certificates. Both callbacks and promises are supported.
react-native-cert-pinner: This plugin allows us to pin the public key. Unlike the plugins above, we can use fetch and other utilities directly. The pinning occurs before native JS is run. Also, there is no requirement to define hashes in the request itself.
react-native-trustkit: this is a wrapper plugin for the iOS Trustkit library. This library is available for iOS only.
Currently, certificate pinning is only available via cordova-plugin-advanced-http. Advanced HTTP is a versatile plugin that can be used to perform complex HTTP operations like SSL pinning, certificate-based auth, and complex file operations.
Theoretically, pinning secures the connection between the client (app) and the server. Practically, rogue pinsets can be inserted via tampered apps. Therefore, it's advisable to use Pinning with Attestation Checks like SafetyNet.
If the pinned certificate changes regularly, the application has to be updated too. App Store updates can take multiple days and have a certain level of uncertainty involved. This may cause unintended service outages to end-users.