Merge "Adding OWNERS to qs package" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index f0c01eea..c600df1 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -39342,6 +39342,7 @@
 
   public class NetworkSecurityPolicy {
     method public static android.security.NetworkSecurityPolicy getInstance();
+    method @FlaggedApi("android.security.certificate_transparency_configuration") public boolean isCertificateTransparencyVerificationRequired(@NonNull String);
     method public boolean isCleartextTrafficPermitted();
     method public boolean isCleartextTrafficPermitted(String);
   }
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index 0c4eeda..e679d20 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -16,6 +16,8 @@
 
 package android.security;
 
+import android.annotation.FlaggedApi;
+import android.annotation.NonNull;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.security.net.config.ApplicationConfig;
@@ -26,9 +28,6 @@
  *
  * <p>Network stacks/components should honor this policy to make it possible to centrally control
  * the relevant aspects of network security behavior.
- *
- * <p>The policy currently consists of a single flag: whether cleartext network traffic is
- * permitted. See {@link #isCleartextTrafficPermitted()}.
  */
 public class NetworkSecurityPolicy {
 
@@ -94,6 +93,22 @@
     }
 
     /**
+     * Returns {@code true} if Certificate Transparency information is required to be verified by
+     * the client in TLS connections to {@code hostname}.
+     *
+     * <p>See RFC6962 section 3.3 for more details.
+     *
+     * @param hostname hostname to check whether certificate transparency verification is required
+     * @return {@code true} if certificate transparency verification is required and {@code false}
+     *     otherwise
+     */
+    @FlaggedApi(Flags.FLAG_CERTIFICATE_TRANSPARENCY_CONFIGURATION)
+    public boolean isCertificateTransparencyVerificationRequired(@NonNull String hostname) {
+        return libcore.net.NetworkSecurityPolicy.getInstance()
+                .isCertificateTransparencyVerificationRequired(hostname);
+    }
+
+    /**
      * Handle an update to the system or user certificate stores.
      * @hide
      */
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 28ef70b..b56bef3 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -1,6 +1,13 @@
 package: "android.security"
 
 flag {
+    name: "certificate_transparency_configuration"
+    namespace: "network_security"
+    description: "Enable certificate transparency setting in the network security config"
+    bug: "28746284"
+}
+
+flag {
     name: "fsverity_api"
     namespace: "hardware_backed_security"
     description: "Feature flag for fs-verity API"
diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java
index 801eceb..4cc870b 100644
--- a/core/java/android/security/net/config/ApplicationConfig.java
+++ b/core/java/android/security/net/config/ApplicationConfig.java
@@ -16,10 +16,15 @@
 
 package android.security.net.config;
 
+import static android.security.Flags.certificateTransparencyConfiguration;
+
+import android.annotation.NonNull;
 import android.util.Pair;
+
 import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
+
 import javax.net.ssl.X509TrustManager;
 
 /**
@@ -147,6 +152,22 @@
         return getConfigForHostname(hostname).isCleartextTrafficPermitted();
     }
 
+    /**
+     * Returns {@code true} if Certificate Transparency information is required to be verified by
+     * the client in TLS connections to {@code hostname}.
+     *
+     * <p>See RFC6962 section 3.3 for more details.
+     *
+     * @param hostname hostname to check whether certificate transparency verification is required
+     * @return {@code true} if certificate transparency verification is required and {@code false}
+     *     otherwise
+     */
+    public boolean isCertificateTransparencyVerificationRequired(@NonNull String hostname) {
+        return certificateTransparencyConfiguration()
+                ? getConfigForHostname(hostname).isCertificateTransparencyVerificationRequired()
+                : NetworkSecurityConfig.DEFAULT_CERTIFICATE_TRANSPARENCY_VERIFICATION_REQUIRED;
+    }
+
     public void handleTrustStorageUpdate() {
         synchronized(mLock) {
             // If the config is uninitialized then there is no work to be done to handle an update,
diff --git a/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
index a708f5b..801b32b 100644
--- a/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
+++ b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
@@ -40,6 +40,6 @@
 
     @Override
     public boolean isCertificateTransparencyVerificationRequired(String hostname) {
-        return false;
+        return mConfig.isCertificateTransparencyVerificationRequired(hostname);
     }
 }
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index 00872fb..129ae63 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -38,9 +38,12 @@
     public static final boolean DEFAULT_CLEARTEXT_TRAFFIC_PERMITTED = true;
     /** @hide */
     public static final boolean DEFAULT_HSTS_ENFORCED = false;
+    /** @hide */
+    public static final boolean DEFAULT_CERTIFICATE_TRANSPARENCY_VERIFICATION_REQUIRED = false;
 
     private final boolean mCleartextTrafficPermitted;
     private final boolean mHstsEnforced;
+    private final boolean mCertificateTransparencyVerificationRequired;
     private final PinSet mPins;
     private final List<CertificatesEntryRef> mCertificatesEntryRefs;
     private Set<TrustAnchor> mAnchors;
@@ -48,10 +51,15 @@
     private NetworkSecurityTrustManager mTrustManager;
     private final Object mTrustManagerLock = new Object();
 
-    private NetworkSecurityConfig(boolean cleartextTrafficPermitted, boolean hstsEnforced,
-            PinSet pins, List<CertificatesEntryRef> certificatesEntryRefs) {
+    private NetworkSecurityConfig(
+            boolean cleartextTrafficPermitted,
+            boolean hstsEnforced,
+            boolean certificateTransparencyVerificationRequired,
+            PinSet pins,
+            List<CertificatesEntryRef> certificatesEntryRefs) {
         mCleartextTrafficPermitted = cleartextTrafficPermitted;
         mHstsEnforced = hstsEnforced;
+        mCertificateTransparencyVerificationRequired = certificateTransparencyVerificationRequired;
         mPins = pins;
         mCertificatesEntryRefs = certificatesEntryRefs;
         // Sort the certificates entry refs so that all entries that override pins come before
@@ -104,6 +112,11 @@
         return mHstsEnforced;
     }
 
+    // TODO(b/28746284): add exceptions for user-added certificates and enterprise overrides.
+    public boolean isCertificateTransparencyVerificationRequired() {
+        return mCertificateTransparencyVerificationRequired;
+    }
+
     public PinSet getPins() {
         return mPins;
     }
@@ -208,6 +221,9 @@
         private boolean mHstsEnforced = DEFAULT_HSTS_ENFORCED;
         private boolean mCleartextTrafficPermittedSet = false;
         private boolean mHstsEnforcedSet = false;
+        private boolean mCertificateTransparencyVerificationRequired =
+                DEFAULT_CERTIFICATE_TRANSPARENCY_VERIFICATION_REQUIRED;
+        private boolean mCertificateTransparencyVerificationRequiredSet = false;
         private Builder mParentBuilder;
 
         /**
@@ -313,12 +329,35 @@
             return mCertificatesEntryRefs;
         }
 
+        Builder setCertificateTransparencyVerificationRequired(boolean required) {
+            mCertificateTransparencyVerificationRequired = required;
+            mCertificateTransparencyVerificationRequiredSet = true;
+            return this;
+        }
+
+        private boolean getCertificateTransparencyVerificationRequired() {
+            if (mCertificateTransparencyVerificationRequiredSet) {
+                return mCertificateTransparencyVerificationRequired;
+            }
+            if (mParentBuilder != null) {
+                return mParentBuilder.getCertificateTransparencyVerificationRequired();
+            }
+            return DEFAULT_CERTIFICATE_TRANSPARENCY_VERIFICATION_REQUIRED;
+        }
+
         public NetworkSecurityConfig build() {
             boolean cleartextPermitted = getEffectiveCleartextTrafficPermitted();
             boolean hstsEnforced = getEffectiveHstsEnforced();
+            boolean certificateTransparencyVerificationRequired =
+                    getCertificateTransparencyVerificationRequired();
             PinSet pinSet = getEffectivePinSet();
             List<CertificatesEntryRef> entryRefs = getEffectiveCertificatesEntryRefs();
-            return new NetworkSecurityConfig(cleartextPermitted, hstsEnforced, pinSet, entryRefs);
+            return new NetworkSecurityConfig(
+                    cleartextPermitted,
+                    hstsEnforced,
+                    certificateTransparencyVerificationRequired,
+                    pinSet,
+                    entryRefs);
         }
     }
 }
diff --git a/core/java/android/security/net/config/XmlConfigSource.java b/core/java/android/security/net/config/XmlConfigSource.java
index 311a8d2..b1c1479 100644
--- a/core/java/android/security/net/config/XmlConfigSource.java
+++ b/core/java/android/security/net/config/XmlConfigSource.java
@@ -171,6 +171,11 @@
         return new Domain(domain, includeSubdomains);
     }
 
+    private boolean parseCertificateTransparency(XmlResourceParser parser)
+            throws IOException, XmlPullParserException, ParserException {
+        return parser.getAttributeBooleanValue(null, "enabled", false);
+    }
+
     private CertificatesEntryRef parseCertificatesEntry(XmlResourceParser parser,
             boolean defaultOverridePins)
             throws IOException, XmlPullParserException, ParserException {
@@ -226,7 +231,6 @@
         boolean seenPinSet = false;
         boolean seenTrustAnchors = false;
         boolean defaultOverridePins = configType == CONFIG_DEBUG;
-        String configName = parser.getName();
         int outerDepth = parser.getDepth();
         // Add this builder now so that this builder occurs before any of its children. This
         // makes the final build pass easier.
@@ -279,6 +283,15 @@
                             "Nested domain-config not allowed in " + getConfigString(configType));
                 }
                 builders.addAll(parseConfigEntry(parser, seenDomains, builder, configType));
+            } else if ("certificateTransparency".equals(tagName)) {
+                if (configType != CONFIG_BASE && configType != CONFIG_DOMAIN) {
+                    throw new ParserException(
+                            parser,
+                            "certificateTransparency not allowed in "
+                                    + getConfigString(configType));
+                }
+                builder.setCertificateTransparencyVerificationRequired(
+                        parseCertificateTransparency(parser));
             } else {
                 XmlUtils.skipCurrentTag(parser);
             }