What is SSL Pinning ?
A practical introduction to analyzing certificate pinning in Android applications.
What is SSL & TLS?
SSL = Secure Sockets Layer. TLS = Transport Layer Security.
SSL was the original protocol used to secure network communication between a client and server. TLS is the modern protocol used to secure communications.
What is SSL/TLS certificate pinning?
Normal TLS says "I trust certificates that chain to an acceptable trusted CA." Certificate pinning adds another restriction: "For this particular server, I expect this specific certificate or public key."
Normal validation
api.example.com
↓
Certificate
↓
Trusted CA
↓
VALIDPinning adds:
Certificate
↓
Trusted CA
+
Expected public key/certificate
↓
VALIDWhy was certificate pinning introduced?
Consider a normal CA ecosystem. Your device may trust hundreds of certificate authorities.
Android trust store
CA 1
CA 2
CA 3
CA 4
CA 5
...
CA NSuppose the legitimate server has:
api.example.com
↓
Certificate
↓
CA XIf another trusted CA can issue a certificate for: api.example.com, then ordinary CA validation could potentially accept it.
Pinning says:
I don't merely trust "any valid certificate."
I expect THIS certificate/public key.SSL Pinning Implementation:
Android framework/config ( network configure xml file ) Java/Kotlin custom ( application code java level ) HTTP library ( Okhttp or similar ) Native ( .so libraries ) Hybrid ( Java + JNI + Native )
How would your assessment identify Java pinning?
During static analysis, you would look for things such as:
CertificatePinner
TrustManager
X509TrustManager
checkServerTrusted
SSLContext
SSLSocketFactory
KeyStore
CertificateFactory
HostnameVerifierAnd for custom logic:
MessageDigest
SHA-256
X509Certificate
getPublicKey()
checkServerTrusted()The presence of:
getPublicKey() combined with: SHA-256 and a hardcoded value is particularly interesting.Conceptually:
getPublicKey()
↓
MessageDigest SHA-256
↓
compare against hardcoded valueThat strongly suggests public-key pinning logic.
Native-level SSL pinning
An Android application doesn't have to perform TLS entirely in Java/Kotlin. It can use: Java/Kotlin -> JNI -> Native C/C++ -> TLS library -> Socket The native library might use a TLS implementation such as:
BoringSSL
OpenSSL
mbedTLS
custom TLS implementation
The exact implementation depends on the application.Native pinning architecture
Android application
|
↓
JNI
|
↓
libnative.so
|
+---- TLS initialization
|
+---- certificate loading
|
+---- verification callback
|
+---- pin comparison
|
↓
TLS library
|
↓
socketThe pinning logic could therefore be completely absent from Java. You might search the APK's: for native libraries. lib/arm64-v8a/ lib/armeabi-v7a/ lib/x86_64/
Native certificate verification , conceptually
certificate = get_peer_certificate();
public_key = extract_public_key(certificate);
hash = sha256(public_key);
if (memcmp(hash, expected_pin, 32) != 0) {
return VERIFY_FAILED;
}
return VERIFY_SUCCESS;The actual implementation might be heavily optimized, obfuscated, split between several functions, or delegated to a TLS library callback.
Related Research
Flutter App SSL Pinning Bypass Using ReFlutter
A simple workflow to extract, merge, patch, sign, and install a Flutter APK for security testing.
Android Proxy Settings with iptables
A simple technique to redirect Android HTTPS traffic to Burp Suite when the application ignores proxy settings.
HTTP Toolkit to Solve the Simcard required application proxy
A simple technique to intercept Android application traffic when the app works only over mobile data and ignores traditional proxy settings.