Certificate Transparency for Android and JVM

repository·main·Indexed 41 days ago

https://github.com/appmattus/certificatetransparency

A library providing Certificate Transparency (CT) support for Android and JVM applications to protect against man-in-the-middle attacks. It offers integration for OkHttp, Retrofit, HttpURLConnection, and Volley, and supports configuration via the Java Security Provider on Android. Features include a customizable network interceptor, certificate chain cleaning, and manual certificate revocation management.

Tokens
5.5K
Snippets
19
Records
26
Agent score
50%

What's inside Certificate Transparency

  1. What is Certificate Transparency

    main

    Certificate Transparency (CT) is an open framework for monitoring and auditing SSL certificates in near real-time. It aims to detect certificates that are mistakenly issued or maliciously acquired from Certificate Authorities (CAs), and to identify rogue CAs.

    CT relies on a network of publicly accessible log servers. When a CA issues a certificate, it is submitted to these logs. The log server responds with a Signed Certificate Timestamp (SCT), which serves as a cryptographic promise that the certificate will be added to the logs within a maximum merge delay of 24 hours.

    User agents (such as web browsers and mobile apps) use the SCT to verify the validity of a domain's certificate. The three primary goals of CT are:

    • Making it difficult to issue certificates without the domain owner's knowledge.
    • Providing auditing and monitoring to spot mis-issued certificates.
    • Protecting users from mis-issued certificates.
  2. Configure Certificate Transparency via Java Security Provider on Android

    main

    On Android, the recommended approach is to configure certificate transparency through the Java Security Provider at app startup using installCertificateTransparencyProvider.

    Advantages:

    • Works across all network types, including WebViews, without additional setup.

    Limitations & Warnings:

    • WebViews on Android 6.0 (API 23) or lower: Do not use installCertificateTransparencyProvider on these versions as it will cause issues.
    • JVM Compatibility: Using the Java Security Provider may not work on all JVMs; if you are not on Android, use alternative integration methods (like OkHttp or Retrofit).

    Configuration Options:

    • logger: Set a logger (e.g., BasicAndroidCTLogger). Note that logs may contain sensitive hostnames and CT results.
    • diskCache: Set a disk cache (e.g., AndroidDiskCache).
    • Exclusions/Inclusions: Use - to exclude domains/subdomains and + to include/override exclusions for specific subdomains.
    class SampleApplication : Application() {
        override fun onCreate() {
            super.onCreate()
    
            installCertificateTransparencyProvider {
                // Setup a logger
                logger = BasicAndroidCTLogger(BuildConfig.DEBUG)
    
                // Setup disk cache
                diskCache = AndroidDiskCache(applicationContext)
    
                // Exclude any subdomain but not "appmattus.com" with no subdomain
                -"*.appmattus.com"
    
                // Exclude specified domain
                -"example.com"
    
                // Override the exclusion by including a specific subdomain
                +"allowed.appmattus.com"
            }
        }
    }
  3. Configure host exclusions for the OkHttp Certificate Transparency interceptor

    main

    When using the certificateTransparencyInterceptor, you can specify which hosts should bypass certificate transparency checks using a DSL.

    • Use the minus operator (-) to exclude a domain or a wildcard pattern (e.g., "*.example.com").
    • Use the plus operator (+) to explicitly include a specific subdomain, which overrides any broader exclusion patterns.
    val interceptor = certificateTransparencyInterceptor {
        // Exclude any subdomain but not "appmattus.com" with no subdomain
        -"*.appmattus.com"
    
        // Exclude specified domain
        -"example.com"
    
        // Override the exclusion by include a specific subdomain
        +"allowed.appmattus.com"
    }
  4. Verify certificates using X509TrustManager

    main

    For non-HTTPS connections, you can integrate Certificate Transparency verification by wrapping an existing X509TrustManager with the certificateTransparencyTrustManager function. This allows you to leverage the library's CT verification logic within standard Java/Android trust management flows.

    val wrappedTrustManager = certificateTransparencyTrustManager(originalTrustManager)
  5. Integrate Certificate Transparency with Volley

    main

    To use Certificate Transparency checks with the Volley networking library, you must override the createConnection method when initializing your RequestQueue. This is done by providing a custom HurlStack implementation. Inside createConnection, wrap the existing hostnameVerifier of any HttpsURLConnection with certificateTransparencyHostnameVerifier.

    val requestQueue = Volley.newRequestQueue(applicationContext, object : HurlStack() {
        override fun createConnection(url: URL): HttpURLConnection {
            val connection = super.createConnection(url)
            if (connection is HttpsURLConnection) {
                connection.hostnameVerifier = certificateTransparencyHostnameVerifier(connection.hostnameVerifier)
            }
            return connection
        }
    })
  6. Exclude specific hosts from Certificate Transparency checks

    main

    When using certificateTransparencyHostnameVerifier, you can provide a configuration block to exclude certain domains or subdomains from CT enforcement.

    Exclusion rules follow these patterns:

    • -"*.domain.com": Excludes all subdomains of a domain.
    • -"domain.com": Excludes a specific domain.
    • +"sub.domain.com": Overrides an exclusion to allow a specific subdomain to be checked.

    This is useful for interacting with legacy servers or specific hosts that do not support Certificate Transparency.

    connection.hostnameVerifier = certificateTransparencyHostnameVerifier(connection.hostnameVerifier) {
        // Exclude any subdomain but not "appmattus.com" with no subdomain
        -"*.appmattus.com"
    
        // Exclude specified domain
        -"example.com"
    
        // Override the exclusion by include a specific subdomain
        +"allowed.appmattus.com"
    }
  7. Install Certificate Transparency for Android or JVM

    main

    Depending on your target platform, include the appropriate dependency in your build.gradle file.

    For Android modules: Use the android dependency to ensure necessary ProGuard rules are included.

    For Java library modules: Use the standard dependency.

    Important Requirements:

    • The library uses Java 8+ language features.
    • If you need to support Android 7 (API 25) or lower, you must enable Desugaring.
    // Android modules
    implementation("com.appmattus.certificatetransparency:certificatetransparency-android:<latest-version>")
    
    // Java library modules
    implementation("com.appmattus.certificatetransparency:certificatetransparency:<latest-version>")
  8. Integrate Certificate Transparency with HttpURLConnection

    main

    To use Certificate Transparency with HttpURLConnection, you must wrap the existing hostnameVerifier of an HttpsURLConnection instance before calling connect(). This ensures that CT checks are performed alongside standard hostname verification.

    Note: It is recommended to upgrade from HttpURLConnection to OkHttp if possible, as the version built into Android is static and does not receive security updates.

    val connection = URL("https://www.appmattus.com").openConnection()
    if (connection is HttpsURLConnection) {
        connection.hostnameVerifier = certificateTransparencyHostnameVerifier(connection.hostnameVerifier)
    }
  9. Exclude specific hosts from Certificate Transparency checks in Volley

    main

    When using certificateTransparencyHostnameVerifier, you can provide a trailing lambda to define exclusions and inclusions for specific domains.

    • Use the unary minus operator (-) to exclude a domain or a wildcard pattern (e.g., "*.example.com").
    • Use the unary plus operator (+) to explicitly include a specific subdomain, which overrides any broader exclusion patterns.
    connection.hostnameVerifier = certificateTransparencyHostnameVerifier(connection.hostnameVerifier) {
        // Exclude any subdomain but not "appmattus.com" with no subdomain
        "*.appmattus.com".unaryMinus()
    
        // Exclude specified domain
        "example.com".unaryMinus()
    
        // Override the exclusion by include a specific subdomain
        "allowed.appmattus.com".unaryPlus()
    }