Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f65df85 authored by Thiébaud Weksteen's avatar Thiébaud Weksteen
Browse files

Add checkServerTrusted variant to X509TrustManagerExtensions

This variant passes down the OCSP and TLS data that may be required to
validate the Certificate Transparency status of a certificate.

This is required for network stacks that are not able to pass down an
SSLSession nor a Socket (e.g., Cronet).

Bug: 293505388
Bug: 319829948
Bug: 377159091
Test: build
API-Coverage-Bug: 376139811
Flag: android.net.platform.flags.x509_extensions_certificate_transparency
Change-Id: I0304c97e799452a51916174788ba7dd6c9a82fb6
parent 7c3fc3b8
Loading
Loading
Loading
Loading
+9 −0
Original line number Original line Diff line number Diff line
@@ -105,6 +105,7 @@ aconfig_declarations_group {
        "com.android.server.flags.services-aconfig-java",
        "com.android.server.flags.services-aconfig-java",
        "com.android.text.flags-aconfig-java",
        "com.android.text.flags-aconfig-java",
        "com.android.window.flags.window-aconfig-java",
        "com.android.window.flags.window-aconfig-java",
        "conscrypt_exported_aconfig_flags_lib",
        "device_policy_aconfig_flags_lib",
        "device_policy_aconfig_flags_lib",
        "display_flags_lib",
        "display_flags_lib",
        "dropbox_flags_lib",
        "dropbox_flags_lib",
@@ -194,6 +195,14 @@ java_aconfig_library {
    defaults: ["framework-minus-apex-aconfig-java-defaults"],
    defaults: ["framework-minus-apex-aconfig-java-defaults"],
}
}


// Conscrypt
java_aconfig_library {
    name: "conscrypt_exported_aconfig_flags_lib",
    aconfig_declarations: "conscrypt-aconfig-flags",
    mode: "exported",
    defaults: ["framework-minus-apex-aconfig-java-defaults"],
}

// Telecom
// Telecom
java_aconfig_library {
java_aconfig_library {
    name: "telecom_flags_core_java_lib",
    name: "telecom_flags_core_java_lib",
+1 −0
Original line number Original line Diff line number Diff line
@@ -29836,6 +29836,7 @@ package android.net.http {
  public class X509TrustManagerExtensions {
  public class X509TrustManagerExtensions {
    ctor public X509TrustManagerExtensions(javax.net.ssl.X509TrustManager) throws java.lang.IllegalArgumentException;
    ctor public X509TrustManagerExtensions(javax.net.ssl.X509TrustManager) throws java.lang.IllegalArgumentException;
    method public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(java.security.cert.X509Certificate[], String, String) throws java.security.cert.CertificateException;
    method public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(java.security.cert.X509Certificate[], String, String) throws java.security.cert.CertificateException;
    method @FlaggedApi("android.net.platform.flags.x509_extensions_certificate_transparency") @NonNull public java.util.List<java.security.cert.X509Certificate> checkServerTrusted(@NonNull java.security.cert.X509Certificate[], @Nullable byte[], @Nullable byte[], @NonNull String, @NonNull String) throws java.security.cert.CertificateException;
    method public boolean isSameTrustConfiguration(String, String);
    method public boolean isSameTrustConfiguration(String, String);
    method public boolean isUserAddedCertificate(java.security.cert.X509Certificate);
    method public boolean isUserAddedCertificate(java.security.cert.X509Certificate);
  }
  }
+8 −0
Original line number Original line Diff line number Diff line
@@ -28,3 +28,11 @@ flag {
    purpose: PURPOSE_BUGFIX
    purpose: PURPOSE_BUGFIX
  }
  }
}
}

flag {
  name: "x509_extensions_certificate_transparency"
  is_exported: true
  namespace: "network_security"
  description: "Flag to use checkServerTrusted to verify SCTs in OCSP and TLS Data"
  bug: "319829948"
}
+84 −4
Original line number Original line Diff line number Diff line
@@ -16,6 +16,13 @@


package android.net.http;
package android.net.http;


import static com.android.org.conscrypt.flags.Flags.certificateTransparencyCheckservertrustedApi;

import android.annotation.FlaggedApi;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SuppressLint;
import android.net.platform.flags.Flags;
import android.security.net.config.UserCertificateSource;
import android.security.net.config.UserCertificateSource;


import com.android.org.conscrypt.TrustManagerImpl;
import com.android.org.conscrypt.TrustManagerImpl;
@@ -24,6 +31,7 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Method;
import java.security.cert.CertificateException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.security.cert.X509Certificate;
import java.util.Collections;
import java.util.List;
import java.util.List;


import javax.net.ssl.X509TrustManager;
import javax.net.ssl.X509TrustManager;
@@ -31,9 +39,9 @@ import javax.net.ssl.X509TrustManager;
/**
/**
 * X509TrustManager wrapper exposing Android-added features.
 * X509TrustManager wrapper exposing Android-added features.
 * <p>
 * <p>
 * The checkServerTrusted method allows callers to perform additional
 * The checkServerTrusted methods allow callers to provide some additional
 * verification of certificate chains after they have been successfully verified
 * context for the verification. This is particularly useful when an SSLEngine
 * by the platform.
 * or SSLSocket is not available.
 * </p>
 * </p>
 */
 */
public class X509TrustManagerExtensions {
public class X509TrustManagerExtensions {
@@ -42,6 +50,7 @@ public class X509TrustManagerExtensions {
    // Methods to use when mDelegate is not a TrustManagerImpl and duck typing is being used.
    // Methods to use when mDelegate is not a TrustManagerImpl and duck typing is being used.
    private final X509TrustManager mTrustManager;
    private final X509TrustManager mTrustManager;
    private final Method mCheckServerTrusted;
    private final Method mCheckServerTrusted;
    private final Method mCheckServerTrustedOcspAndTlsData;
    private final Method mIsSameTrustConfiguration;
    private final Method mIsSameTrustConfiguration;


    /**
    /**
@@ -55,6 +64,7 @@ public class X509TrustManagerExtensions {
            mDelegate = (TrustManagerImpl) tm;
            mDelegate = (TrustManagerImpl) tm;
            mTrustManager = null;
            mTrustManager = null;
            mCheckServerTrusted = null;
            mCheckServerTrusted = null;
            mCheckServerTrustedOcspAndTlsData = null;
            mIsSameTrustConfiguration = null;
            mIsSameTrustConfiguration = null;
            return;
            return;
        }
        }
@@ -69,8 +79,19 @@ public class X509TrustManagerExtensions {
                    String.class);
                    String.class);
        } catch (NoSuchMethodException e) {
        } catch (NoSuchMethodException e) {
            throw new IllegalArgumentException("Required method"
            throw new IllegalArgumentException("Required method"
                    + " checkServerTrusted(X509Certificate[], String, String, String) missing");
                    + " checkServerTrusted(X509Certificate[], String, String) missing");
        }
        }
        // Check that the OCSP and TlsData aware checkServerTrusted is present.
        Method checkServerTrustedOcspAndTlsData = null;
        try {
            checkServerTrustedOcspAndTlsData = tm.getClass().getMethod("checkServerTrusted",
                    X509Certificate[].class,
                    Byte[].class,
                    Byte[].class,
                    String.class,
                    String.class);
        } catch (ReflectiveOperationException ignored) { }
        mCheckServerTrustedOcspAndTlsData = checkServerTrustedOcspAndTlsData;
        // Get the option isSameTrustConfiguration method.
        // Get the option isSameTrustConfiguration method.
        Method isSameTrustConfiguration = null;
        Method isSameTrustConfiguration = null;
        try {
        try {
@@ -114,6 +135,65 @@ public class X509TrustManagerExtensions {
        }
        }
    }
    }


    /**
     * Verifies the given certificate chain.
     *
     * <p>See {@link X509TrustManager#checkServerTrusted(X509Certificate[], String)} for a
     * description of the chain and authType parameters. The final parameter, host, should be the
     * hostname of the server.</p>
     *
     * <p>ocspData and tlsSctData may be provided to verify any Signed Certificate Timestamp (SCT)
     * attached to the connection. These are ASN.1 octet strings (SignedCertificateTimestampList)
     * as described in RFC 6962, Section 3.3. Note that SCTs embedded in the certificate chain
     * will automatically be processed.
     * </p>
     *
     * @throws CertificateException if the chain does not verify correctly.
     * @throws IllegalArgumentException if the TrustManager is not compatible.
     * @return the properly ordered chain used for verification as a list of X509Certificates.
     */
    @FlaggedApi(Flags.FLAG_X509_EXTENSIONS_CERTIFICATE_TRANSPARENCY)
    @NonNull
    public List<X509Certificate> checkServerTrusted(
            @SuppressLint("ArrayReturn") @NonNull X509Certificate[] chain,
            @Nullable byte[] ocspData,
            @Nullable byte[] tlsSctData,
            @NonNull String authType,
            @NonNull String host) throws CertificateException {
        List<X509Certificate> result;
        if (mDelegate != null) {
            if (certificateTransparencyCheckservertrustedApi()) {
                result = mDelegate.checkServerTrusted(chain, ocspData, tlsSctData, authType, host);
                return result == null ? Collections.emptyList() : result;
            } else {
                // The conscrypt mainline module does not have the required method.
                throw new IllegalArgumentException("Required method"
                    + " checkServerTrusted(X509Certificate[], byte[], byte[], String, String)"
                    + " not available in TrustManagerImpl");
            }
        }
        if (mCheckServerTrustedOcspAndTlsData == null) {
            throw new IllegalArgumentException("Required method"
                    + " checkServerTrusted(X509Certificate[], byte[], byte[], String, String)"
                    + " missing");
        }
        try {
            result = (List<X509Certificate>) mCheckServerTrustedOcspAndTlsData.invoke(mTrustManager,
                    ocspData, tlsSctData, chain, authType, host);
            return result == null ? Collections.emptyList() : result;
        } catch (IllegalAccessException e) {
            throw new CertificateException("Failed to call checkServerTrusted", e);
        } catch (InvocationTargetException e) {
            if (e.getCause() instanceof CertificateException) {
                throw (CertificateException) e.getCause();
            }
            if (e.getCause() instanceof RuntimeException) {
                throw (RuntimeException) e.getCause();
            }
            throw new CertificateException("checkServerTrusted failed", e.getCause());
        }
    }

    /**
    /**
     * Checks whether a CA certificate is added by an user.
     * Checks whether a CA certificate is added by an user.
     *
     *