We use TrustKit Android to enable SSL pinning in our android apps, and then I found there are some misunderstandings before adopting. This article shares the problems and solutions we encountered when integrating TrustKit Android.
- Do without TrustKit when Min SDK 24 and above
TrustKit supports public key SSL pinning down to API level 17. If the app’s min SDK version is 24 and above, it needn’t TrustKit Android. We can enable SSL Pinning directly by Network Security Configuration.
Even on the device of API 24 or above, once TrustKit has been initialized and the OKHTTPClient or HttpsURLConnection’s SSLSocketFactory
has been set, it will verify the server's certificate chain against the configured pinning policy whenever an HTTPS connection is initiated.
- Single
<domain-config>
Single<domain>
TrustKit can’t support multi <domain>
under the same <domain-config>
, it only deploys SSL public key pinning at the last domain, for example
<domain-config>
<domain includeSubdomains="true">google.com</domain>
<domain includeSubdomains="true">flurry.com</domain>
<domain includeSubdomains="true">yahoo.com</domain>
<pin-set>
<pin digest="SHA-256">k3XnEYQCK79AtL9GYnT/nyhsabas03V+bhRQYHQbpXU=</pin>
<pin digest="SHA-256">2kOi4HdYYsvTR1sTIR7RHwlf2SescTrpza9ZrWy7poQ=</pin>
</pin-set>
</domain-config>
TrustKit only verifies the domain yahoo.com
’s the certificate chain. Neither flurry.com
nor google.com
. If we want to enable SSL pinning to all the domains, even the same certificate chain, we need to separate the domain-config:
<domain-config>
<domain includeSubdomains="true">google.com</domain>
<pin-set>
<pin digest="SHA-256">k3XnEYQCK79AtL9GYnT/nyhsabas03V+bhRQYHQbpXU=</pin>
<pin digest="SHA-256">2kOi4HdYYsvTR1sTIR7RHwlf2SescTrpza9ZrWy7poQ=</pin>
</pin-set>
</domain-config><domain-config>
<domain includeSubdomains="true">flurry.com</domain>
<pin-set>
<pin digest="SHA-256">k3XnEYQCK79AtL9GYnT/nyhsabas03V+bhRQYHQbpXU=</pin>
<pin digest="SHA-256">2kOi4HdYYsvTR1sTIR7RHwlf2SescTrpza9ZrWy7poQ=</pin>
</pin-set>
</domain-config><domain-config>
<domain includeSubdomains="true">yahoo.com</domain>
<pin-set>
<pin digest="SHA-256">k3XnEYQCK79AtL9GYnT/nyhsabas03V+bhRQYHQbpXU=</pin>
<pin digest="SHA-256">2kOi4HdYYsvTR1sTIR7RHwlf2SescTrpza9ZrWy7poQ=</pin>
</pin-set>
</domain-config>
For this issue, we can refer to its test cases:
https://github.com/datatheorem/TrustKit-Android/blob/master/trustkit/src/androidTest/res/xml/network_security_config.xml
- Single OKHttpClient Single Domain
TrustKit doesn’t support for pinning multiple domains with a single OkHttpClient. For example, if you have 3 API servers, you need to create 3 OkHttpClient instances for different domains.
Fortunately, TrustKit corrects this limitation in this PR so that we can use the same OkHttpClient instance with different domains, on TrustKit Android v1.1.3.
- Expiration Date of Pinning Bypass
The expiration
is the date on which the pins expire. After the date, it doesn’t mean the connection will fail because of expired pinning; it’s the date of disabling pinning.
- Using Charles to verify SSL Pinning
Pinning would fail network requests when Charles proxy is attached. If Charles can decode HTTPS calls from the app or such calls continue to succeed, then pinning is not working.
This is because Pinning is designed to stop the same tricks that Charles Proxy uses. Similar tricks can be deployed by hackers / hostile governments on a large scale.