datatheorem / datatheorem/TrustKit-Android

Implementation fails to enforce pinning (React Native)

Open
#91 4 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Java
Stars
604
Forks
90
Avg merge
1h 29m
Merged PRs (30d)
2

Description

Describe the bug
A clear and concise description of what the bug is.

I've implemented the library as is described in the documentation, without any success in enforcing the certificate pinning.

To Reproduce
Steps to reproduce the behavior.

res/xml/network_security_config.xml

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">www.example.com</domain>
        <pin-set>
            <-- Invalid certificates -->
            <pin digest="SHA-256">AAAAeJFIEmx2Y01oXXXXXXXXXXmmSFZhBXXXXXXXXXX=</pin>
            <pin digest="SHA-256">CCCCxtmctlq2Y73orFOOXXXXXXXXXXZhBXXXXXXXXXX=</pin>
        </pin-set>
    </domain-config>
    <domain-config cleartextTrafficPermitted="true">
        <-- React Native config for debugging the app in Debug mode. I have tried without it and it still fails -->
        <domain includeSubdomains="true">10.0.2.2</domain>
        <domain includeSubdomains="true">localhost</domain>
    </domain-config>
</network-security-config>

MainApplication.java

...
  @Override
  public void onCreate() {
    super.onCreate();
    // Using the default path - res/xml/network_security_config.xml
    TrustKit.initializeWithNetworkSecurityConfiguration(this);

    String serverHostname = null;
    try {
        URL url = new URL("https://www.example.com");
        serverHostname = url.getHost();

        // HttpsUrlConnection
        HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
        connection.setSSLSocketFactory(TrustKit.getInstance().getSSLSocketFactory(serverHostname));
    } catch (MalformedURLException e) {
        System.err.println("MalformedURLException when declaring URL " + e);
    } catch (IOException e) {
        System.err.println("IOException when opening connection " + e);
    }

    // OkHttp 3
    // OkHttpClient client = OkHttpClientProvider.createClientBuilder().sslSocketFactory(TrustKit.getInstance().getSSLSocketFactory(serverHostname),TrustKit.getInstance().getTrustManager(serverHostname)).build();

    OkHttpClient client = new OkHttpClient().newBuilder().sslSocketFactory(TrustKit.getInstance().getSSLSocketFactory(serverHostname),TrustKit.getInstance().getTrustManager(serverHostname)).build();

    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
  }

useValidCertificate.js which is called once the Navigation screens have mounted

export default function useValidCertificate() {
  useEffect(() => {
    (async () => {
      fetch(`https://www.example.com/account/ping`)
        .then(() => {
          console.log('Valid certificate, connected.');
        })
        .catch(() => {
          resetRoot(SECURITY_SCREENS.InvalidCertificate);
        });
    })();
  }, []);
}

Expected behavior
A clear and concise description of what you expected to happen.

The app should navigate to InvalidCertificate screen as it does when using TrustKit library for iOS.
Instead the app is behaving as if the certificate is still valid.

TrustKit configuration
Copy and paste your XML Network Security Policy.

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <domain-config cleartextTrafficPermitted="false">
        <domain includeSubdomains="true">www.example.com</domain>
        <pin-set>
            <-- Invalid certificates -->
            <pin digest="SHA-256">AAAAeJFIEmx2Y01oXXXXXXXXXXmmSFZhBXXXXXXXXXX=</pin>
            <pin digest="SHA-256">CCCCxtmctlq2Y73orFOOXXXXXXXXXXZhBXXXXXXXXXX=</pin>
        </pin-set>
    </domain-config>
    <domain-config cleartextTrafficPermitted="true">
        <-- React Native config for debugging the app in Debug mode. I have tried without it and it still fails -->
        <domain includeSubdomains="true">10.0.2.2</domain>
        <domain includeSubdomains="true">localhost</domain>
    </domain-config>
</network-security-config>

App details:

  • App target SDK: 29
  • App language: React Native
  • Android version to reproduce the bug: Android 10

Additional context
Add any other context about the problem here.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Review MainApplication.java, useValidCertificate.js, and the supplied network_security_config.xml; first trace which Android networking path handles the fetch and how TrustKit is initialized. Reproduce on Android 10 with the provided invalid pins. Done means the request is rejected and the app reaches InvalidCertificate, with the behavior verified by an appropriate regression check.

Written by the indexing model from the issue text.

Assessment

Tech stack
android, java, react-native
Domain
mobile-dev, security
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
32/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.