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
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index e184704..e951708 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -105,6 +105,7 @@
         "com.android.server.flags.services-aconfig-java",
         "com.android.text.flags-aconfig-java",
         "com.android.window.flags.window-aconfig-java",
+        "conscrypt_exported_aconfig_flags_lib",
         "device_policy_aconfig_flags_lib",
         "display_flags_lib",
         "dropbox_flags_lib",
@@ -194,6 +195,14 @@
     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
 java_aconfig_library {
     name: "telecom_flags_core_java_lib",
diff --git a/core/api/current.txt b/core/api/current.txt
index af7d6f1..a2ded05 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -29836,6 +29836,7 @@
   public class X509TrustManagerExtensions {
     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 @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 isUserAddedCertificate(java.security.cert.X509Certificate);
   }
diff --git a/core/java/android/net/flags.aconfig b/core/java/android/net/flags.aconfig
index f7dc790..3e7263d 100644
--- a/core/java/android/net/flags.aconfig
+++ b/core/java/android/net/flags.aconfig
@@ -28,3 +28,11 @@
     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"
+}
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index 280dad0..b44f75a 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -16,6 +16,13 @@
 
 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 com.android.org.conscrypt.TrustManagerImpl;
@@ -24,6 +31,7 @@
 import java.lang.reflect.Method;
 import java.security.cert.CertificateException;
 import java.security.cert.X509Certificate;
+import java.util.Collections;
 import java.util.List;
 
 import javax.net.ssl.X509TrustManager;
@@ -31,9 +39,9 @@
 /**
  * X509TrustManager wrapper exposing Android-added features.
  * <p>
- * The checkServerTrusted method allows callers to perform additional
- * verification of certificate chains after they have been successfully verified
- * by the platform.
+ * The checkServerTrusted methods allow callers to provide some additional
+ * context for the verification. This is particularly useful when an SSLEngine
+ * or SSLSocket is not available.
  * </p>
  */
 public class X509TrustManagerExtensions {
@@ -42,6 +50,7 @@
     // Methods to use when mDelegate is not a TrustManagerImpl and duck typing is being used.
     private final X509TrustManager mTrustManager;
     private final Method mCheckServerTrusted;
+    private final Method mCheckServerTrustedOcspAndTlsData;
     private final Method mIsSameTrustConfiguration;
 
     /**
@@ -55,6 +64,7 @@
             mDelegate = (TrustManagerImpl) tm;
             mTrustManager = null;
             mCheckServerTrusted = null;
+            mCheckServerTrustedOcspAndTlsData = null;
             mIsSameTrustConfiguration = null;
             return;
         }
@@ -69,8 +79,19 @@
                     String.class);
         } catch (NoSuchMethodException e) {
             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.
         Method isSameTrustConfiguration = null;
         try {
@@ -115,6 +136,65 @@
     }
 
     /**
+     * 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.
      *
      * <p>Since {@link X509TrustManager#checkServerTrusted} may allow its parameter {@code chain} to