While researching certificate pinning, I stumbled upon a ‘generic’ implementation flaw allowing remote attackers to bypass the protection that certificate pinning can offer to an application.
If your Java or Android application uses the checkServerTrusted() or getPeerCertificates() APIs to implement certificate pinning, there is a very good chance that your pinning implementation is completely ineffective.
The flaw affects a great number of Java and Android applications that have chosen to implement pinning. It also affects several frameworks and libraries that expose a pinning functionality based on those APIs—increasing the number of affected applications even more.
I consider the impact severe for apps that want pinning to work.
This flaw is a classic “API misuse” issue. Developers use APIs expecting them to return something trusted; but the APIs return something that can instead be abused by attackers. These APIs are commonly used to retrieve the server’s certificate and compare it against a list of certificate ‘pins’ the application holds. However, these APIs return the ‘true’ certificate chain of the server which can be directly controlled by an attacker. The certificate chain needs to be ‘cleaned’ before attempting to compare against pins.
There is no need for local access to the device or application for the attack to work. A remote attacker could serve a malicious certificate list to the client and completely bypass the certificate pinning control while performing a Man-in-the-Middle (MitM) attack.
Certificate pinning is a software control that an application can implement to protect its communications against a special type of MitM attack.
Specifically, it protects application traffic against attackers with the ability to sign certificates using a Certificate Authority (CA) the host system trusts.
These attackers may have gained access to the private key of a trusted CA through several methods:
If an application uses certificate pinning, it can validate that an expected certificate is included in the validated certificate chain (trusted path) between your server’s certificate and a CA.
If there is no pinning control, malicious actors (defined above) are able to intercept traffic anywhere between the application’s users and the web server.
Java/Android applications tend to implement certificate pinning in one of two very different ways:
Both options are very popular. The problem lies in applications or libraries leveraging the second option (SPKI pinning or similar methods).
Java APIs that retrieve the certificates of a SSL connection are poorly documented, resulting in developers misusing them. To implement pinning, what developers want to retrieve is the “trusted certificate path,” as created by the system’s certificate validation routines. What the APIs return is the list of certificates as sent by a potentially malicious server. These two can be different.
During the SSL handshake, web servers send a list of several certificates to clients. Usually, chain[0] holds the end-entity certificate, chain[1] holds an intermediate CA certificate, chain[2] holds maybe another intermediate CA certificate, and chain[3] may or may not hold the root CA certificate for that chain.
But, this is not really a chain. It is just a list of certificates that are hints that a client may or may not use while it attempts to form a trusted path between the server’s end-entity certificate and a CA certificate trusted by the system.
It is the client’s job to create and validate this trusted path for each connection, and a server does its best to help by sending certificates the client may need. The server is free to include any certificate it wants in the list of certificates it sends to the client. These could include certificates that may be completely unrelated and do not sign, or are not signed by any relevant CA.
Let’s see an example. Normally, a server would send the following to a client during the SSL handshake:
Imagine that an attacker has access to the private key of compromised certificate authority Z.
If the attacker manages to redirect client traffic to a malicious web server, an SSL MitM attack is possible because the system trusts CA Z.
However, if the application makes use of certificate pinning, it could pin to the specific public key of any one of the valid certificates—A, B, C, or D. The application should refuse to connect because these do not appear in the new chain while the MitM attack is happening.
There is nothing stopping an attacker from serving the following malicious chain to a client:
In this scenario, a broken chain is presented to the client. The operating system happily validates the connection due to the presence of certificate W (list[0]). It will try to form a valid path between the end-entity certificate W (list[0]) and a CA it trusts, and it trusts CA Z (list[1]). The rest of the certificates are silently ignored by the SSL handshake methods while they construct a new clean chain.
Unfortunately, a developer cannot easily gain access to this new clean chain in standard Java and in past Android versions.
Using the following Java APIs to implement certificate pinning is dangerous:
Using other APIs that just call the previous two under the hood is also dangerous. The following are examples but more may exist:
These APIs are going to return the list of certificates as sent by the server. However, what you really want is the list of certificates in the certificate path that the OS validation routine created and trusts. In other words, in order to implement pinning correctly, you need the clean chain.
The problem is clear. Most certificate pinning implementations follow this pattern, where peerCertificates is the output of one of the previously mentioned APIs (example from OkHttp).
for (int i = 0, size = peerCertificates.size(); i < size; i++) {
X509Certificate x509Certificate = peerCertificates.get(i);
if (pins.contains(sha1(x509Certificate))) return; // Success!
}
Each certificate in the server’s list is compared with each of the hardcoded pins. If the list contains any extra certificates (those that are not part of the trusted certificate path), they are checked as well. In the malicious chain scenario, pinning will still succeed because the list received by the server contains the exact certificates the application might pin to.
There are several ways to fix this implementation flaw; however, each mitigation method has its advantages and disadvantages. Mitigation may differ according to each application’s other requirements.
You shouldn’t take lightly an attempt to construct a trusted path yourself, cleaning the chain in the process. X509 chain validation is a complicated process that is best left to SSL network experts. There are a million ways to shoot yourself in the foot in attempting to do this. You’ve been warned.
As mentioned, this flaw affects several Java and Android applications that implemented certificate pinning via checking received certificates against a list of pins. Some use third-party libraries. Some roll their own pinning. Most are vulnerable. Using those Java APIs to retrieve server certificates is a trap.
I have privately disclosed this information to nine entities so far, including five major e-banking and e-payment applications, popular image sharing applications and others. Four of these entities have resolved the issue already, and the remaining entities are in various stages of the remediation process.
I am certain that many more applications and libraries that contain a broken implementation exist. I advise every application developer to check their implementation.
OkHttp is one of the libraries affected by this flaw. It is a very popular open-source networking library, maintained by Square, and used by several Java and Android applications. It is also part of the Android Open Source Project—the engine that powers HttpUrlConnection as of Android 4.4.
OkHttp has offered a certificate pinning feature to developers since OkHttp 2.1. Unfortunately, it doesn’t validate pins on a sanitized certificate chain, making it vulnerable to attack. An attacker could exploit this weakness to defeat all protection offered by certificate pinning.
I disclosed this through Square’s responsible disclosure program and it was picked up immediately. I’d like to thank Jesse Wilson and the security team at Square for the streamlined process and their excellent work. The issue was assigned CVE-2016-2402.
This flaw has been resolved in OkHttp 3.1.2 and the fix has been backported to OkHttp 2.7.4. I will leave it to Jesse to describe the pains of fixing this in a sensible way; unfortunately, the APIs offered by Java and Android aren’t great. OkHttp fixed this using reflection as described above. There’s an effort going on to change the relevant Java APIs.
If your app uses OkHttp’s certificate pinning feature, you should upgrade to the latest version of the library immediately.
PhoneGap SSL Certificate Checker is a PhoneGap/Cordova plugin used by PhoneGap/Cordova apps to do something like certificate pinning (at least for an initial connection to an endpoint, not all). It is developed by Eddy Verbruggen.
By default, it only conducts end-entity pinning in a safe manner. However, it has a configuration option (checkInCertChain) that allows developers to pin CA certificates as well. If this non-default configuration is used, the pinning implementation becomes insecure and can be bypassed via attack methods discussed above.
The CA-pinning feature has now been disabled and an updated version of the library has been released. I advise everyone to update. I also recommend that the Secure-HTTP Cordova pinning plugin is used instead because its pinning implementation is based on the use of a custom KeyStore.
Understanding whether your application is vulnerable to this flaw can be tricky. For additional details, I created a set of tools and processes to guide you.
[1] http://www.h-online.com/security/news/item/Trustwave-issued-a-man-in-the-middle-certificate-1429982.html
[2] https://googleonlinesecurity.blogspot.gr/2015/03/maintaining-digital-certificate-security.html
[3] I will be talking about the complexities involved in designing certificate pinning solutions in the 2016 OWASP AppSecEU conference.