summaryrefslogtreecommitdiff
path: root/keystore
diff options
context:
space:
mode:
Diffstat (limited to 'keystore')
-rw-r--r--keystore/Android.bp31
-rw-r--r--keystore/java/android/security/AppUriAuthenticationPolicy.aidl19
-rw-r--r--keystore/java/android/security/AppUriAuthenticationPolicy.java241
-rw-r--r--keystore/java/android/security/CredentialManagementApp.java123
-rw-r--r--keystore/java/android/security/Credentials.java2
-rw-r--r--keystore/java/android/security/IKeyChainService.aidl9
-rw-r--r--keystore/java/android/security/KeyChain.java38
-rw-r--r--keystore/java/android/security/UrisToAliases.java138
-rw-r--r--keystore/tests/Android.bp9
9 files changed, 610 insertions, 0 deletions
diff --git a/keystore/Android.bp b/keystore/Android.bp
new file mode 100644
index 000000000000..5db668e48431
--- /dev/null
+++ b/keystore/Android.bp
@@ -0,0 +1,31 @@
+//
+// Copyright (C) 2021 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["frameworks_base_keystore_license"],
+}
+
+// Added automatically by a large-scale-change
+// See: http://go/android-license-faq
+license {
+ name: "frameworks_base_keystore_license",
+ visibility: [":__subpackages__"],
+ license_kinds: [
+ "SPDX-license-identifier-Apache-2.0",
+ ],
+ license_text: [
+ "NOTICE",
+ ],
+}
diff --git a/keystore/java/android/security/AppUriAuthenticationPolicy.aidl b/keystore/java/android/security/AppUriAuthenticationPolicy.aidl
new file mode 100644
index 000000000000..5c52c86f0426
--- /dev/null
+++ b/keystore/java/android/security/AppUriAuthenticationPolicy.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+parcelable AppUriAuthenticationPolicy;
diff --git a/keystore/java/android/security/AppUriAuthenticationPolicy.java b/keystore/java/android/security/AppUriAuthenticationPolicy.java
new file mode 100644
index 000000000000..0244ce97c0d4
--- /dev/null
+++ b/keystore/java/android/security/AppUriAuthenticationPolicy.java
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Set;
+
+/**
+ * The app-URI authentication policy is set by the credential management app. This policy determines
+ * which alias for a private key and certificate pair should be used for authentication.
+ * <p>
+ * The authentication policy should be added as a parameter when calling
+ * {@link KeyChain#createManageCredentialsIntent}.
+ * <p>
+ * Example:
+ * <pre>{@code
+ * AppUriAuthenticationPolicy authenticationPolicy = new AppUriAuthenticationPolicy.Builder()
+ * .addAppAndUriMapping("com.test.pkg", testUri, "testAlias")
+ * .addAppAndUriMapping("com.test2.pkg", testUri1, "testAlias2")
+ * .addAppAndUriMapping("com.test2.pkg", testUri2, "testAlias2")
+ * .build();
+ * Intent requestIntent = KeyChain.createManageCredentialsIntent(authenticationPolicy);
+ * }</pre>
+ * <p>
+ */
+public final class AppUriAuthenticationPolicy implements Parcelable {
+
+ private static final String KEY_AUTHENTICATION_POLICY_APP_TO_URIS =
+ "authentication_policy_app_to_uris";
+ private static final String KEY_AUTHENTICATION_POLICY_APP = "policy_app";
+
+ /**
+ * The mappings from an app and list of URIs to a list of aliases, which will be used for
+ * authentication.
+ * <p>
+ * appPackageName -> uri -> alias
+ */
+ @NonNull
+ private final Map<String, UrisToAliases> mAppToUris;
+
+ private AppUriAuthenticationPolicy(@NonNull Map<String, UrisToAliases> appToUris) {
+ Objects.requireNonNull(appToUris);
+ this.mAppToUris = appToUris;
+ }
+
+ /**
+ * Builder class for {@link AppUriAuthenticationPolicy} objects.
+ */
+ public static final class Builder {
+ private Map<String, UrisToAliases> mPackageNameToUris;
+
+ /**
+ * Initialize a new Builder to construct an {@link AppUriAuthenticationPolicy}.
+ */
+ public Builder() {
+ mPackageNameToUris = new HashMap<>();
+ }
+
+ /**
+ * Adds mappings from an app and URI to an alias, which will be used for authentication.
+ * <p>
+ * If this method is called with a package name and URI that was previously added, the
+ * previous alias will be overwritten.
+ *
+ * @param appPackageName The app's package name to authenticate the user to.
+ * @param uri The URI to authenticate the user to.
+ * @param alias The alias which will be used for authentication.
+ *
+ * @return the same Builder instance.
+ */
+ @NonNull
+ public Builder addAppAndUriMapping(@NonNull String appPackageName, @NonNull Uri uri,
+ @NonNull String alias) {
+ Objects.requireNonNull(appPackageName);
+ Objects.requireNonNull(uri);
+ Objects.requireNonNull(alias);
+ UrisToAliases urisToAliases =
+ mPackageNameToUris.getOrDefault(appPackageName, new UrisToAliases());
+ urisToAliases.addUriToAlias(uri, alias);
+ mPackageNameToUris.put(appPackageName, urisToAliases);
+ return this;
+ }
+
+ /**
+ * Adds mappings from an app and list of URIs to a list of aliases, which will be used for
+ * authentication.
+ * <p>
+ * appPackageName -> uri -> alias
+ *
+ * @hide
+ */
+ @NonNull
+ public Builder addAppAndUriMapping(@NonNull String appPackageName,
+ @NonNull UrisToAliases urisToAliases) {
+ Objects.requireNonNull(appPackageName);
+ Objects.requireNonNull(urisToAliases);
+ mPackageNameToUris.put(appPackageName, urisToAliases);
+ return this;
+ }
+
+ /**
+ * Combines all of the attributes that have been set on the {@link Builder}
+ *
+ * @return a new {@link AppUriAuthenticationPolicy} object.
+ */
+ @NonNull
+ public AppUriAuthenticationPolicy build() {
+ return new AppUriAuthenticationPolicy(mPackageNameToUris);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeMap(mAppToUris);
+ }
+
+ @NonNull
+ public static final Parcelable.Creator<AppUriAuthenticationPolicy> CREATOR =
+ new Parcelable.Creator<AppUriAuthenticationPolicy>() {
+ @Override
+ public AppUriAuthenticationPolicy createFromParcel(Parcel in) {
+ Map<String, UrisToAliases> appToUris = new HashMap<>();
+ in.readMap(appToUris, UrisToAliases.class.getClassLoader());
+ return new AppUriAuthenticationPolicy(appToUris);
+ }
+
+ @Override
+ public AppUriAuthenticationPolicy[] newArray(int size) {
+ return new AppUriAuthenticationPolicy[size];
+ }
+ };
+
+ @Override
+ public String toString() {
+ return "AppUriAuthenticationPolicy{"
+ + "mPackageNameToUris=" + mAppToUris
+ + '}';
+ }
+
+ /**
+ * Return the authentication policy mapping, which determines which alias for a private key
+ * and certificate pair should be used for authentication.
+ * <p>
+ * appPackageName -> uri -> alias
+ */
+ @NonNull
+ public Map<String, Map<Uri, String>> getAppAndUriMappings() {
+ Map<String, Map<Uri, String>> appAndUris = new HashMap<>();
+ for (Map.Entry<String, UrisToAliases> entry : mAppToUris.entrySet()) {
+ appAndUris.put(entry.getKey(), entry.getValue().getUrisToAliases());
+ }
+ return appAndUris;
+ }
+
+ /**
+ * Restore a previously saved {@link AppUriAuthenticationPolicy} from XML.
+ *
+ * @hide
+ */
+ @Nullable
+ public static AppUriAuthenticationPolicy readFromXml(@NonNull XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ AppUriAuthenticationPolicy.Builder builder = new AppUriAuthenticationPolicy.Builder();
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ if (!parser.getName().equals(KEY_AUTHENTICATION_POLICY_APP_TO_URIS)) {
+ continue;
+ }
+ String app = parser.getAttributeValue(null, KEY_AUTHENTICATION_POLICY_APP);
+ UrisToAliases urisToAliases = UrisToAliases.readFromXml(parser);
+ builder.addAppAndUriMapping(app, urisToAliases);
+ }
+ return builder.build();
+ }
+
+ /**
+ * Save the {@link AppUriAuthenticationPolicy} to XML.
+ *
+ * @hide
+ */
+ public void writeToXml(@NonNull XmlSerializer out) throws IOException {
+ for (Map.Entry<String, UrisToAliases> appsToUris : mAppToUris.entrySet()) {
+ out.startTag(null, KEY_AUTHENTICATION_POLICY_APP_TO_URIS);
+ out.attribute(null, KEY_AUTHENTICATION_POLICY_APP, appsToUris.getKey());
+ appsToUris.getValue().writeToXml(out);
+ out.endTag(null, KEY_AUTHENTICATION_POLICY_APP_TO_URIS);
+ }
+ }
+
+ /**
+ * Get the set of aliases found in the policy.
+ *
+ * @hide
+ */
+ public Set<String> getAliases() {
+ Set<String> aliases = new HashSet<>();
+ for (UrisToAliases appsToUris : mAppToUris.values()) {
+ aliases.addAll(appsToUris.getUrisToAliases().values());
+ }
+ return aliases;
+ }
+
+}
diff --git a/keystore/java/android/security/CredentialManagementApp.java b/keystore/java/android/security/CredentialManagementApp.java
new file mode 100644
index 000000000000..cbb23015dbe8
--- /dev/null
+++ b/keystore/java/android/security/CredentialManagementApp.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Objects;
+
+/**
+ * The credential management app has the ability to manage the user's KeyChain credentials on
+ * unmanaged devices. {@link KeyChain#createManageCredentialsIntent} should be used by an app to
+ * request to become the credential management app. The user must approve this request before the
+ * app can manage the user's credentials.
+ * <p>
+ * Note: there can only be one credential management on the device. If another app requests to
+ * become the credential management app and the user approves, then the existing credential
+ * management app will no longer be able to manage credentials.
+ * <p>
+ * The requesting credential management app should include its authentication policy in the
+ * requesting intent. The authentication policy declares which certificates should be used for a
+ * given list of apps and URIs.
+ *
+ * @hide
+ * @see AppUriAuthenticationPolicy
+ */
+public class CredentialManagementApp {
+
+ private static final String TAG = "CredentialManagementApp";
+ private static final String KEY_PACKAGE_NAME = "package_name";
+
+ /**
+ * The credential management app's package name
+ */
+ @NonNull
+ private final String mPackageName;
+
+ /**
+ * The mappings from an app and list of URIs to a list of aliases, which will be used for
+ * authentication.
+ * <p>
+ * appPackageName -> uri -> alias
+ */
+ @NonNull
+ private AppUriAuthenticationPolicy mAuthenticationPolicy;
+
+ public CredentialManagementApp(@NonNull String packageName,
+ @NonNull AppUriAuthenticationPolicy authenticationPolicy) {
+ Objects.requireNonNull(packageName);
+ Objects.requireNonNull(authenticationPolicy);
+ mPackageName = packageName;
+ mAuthenticationPolicy = authenticationPolicy;
+ }
+
+ /**
+ * Returns the package name of the credential management app.
+ */
+ @NonNull
+ public String getPackageName() {
+ return mPackageName;
+ }
+
+ /**
+ * Returns the authentication policy of the credential management app.
+ */
+ @NonNull
+ public AppUriAuthenticationPolicy getAuthenticationPolicy() {
+ return mAuthenticationPolicy;
+ }
+
+ /**
+ * Sets the authentication policy of the credential management app.
+ */
+ public void setAuthenticationPolicy(@Nullable AppUriAuthenticationPolicy authenticationPolicy) {
+ Objects.requireNonNull(authenticationPolicy);
+ mAuthenticationPolicy = authenticationPolicy;
+ }
+
+ /**
+ * Restore a previously saved {@link CredentialManagementApp} from XML.
+ */
+ @Nullable
+ public static CredentialManagementApp readFromXml(@NonNull XmlPullParser parser) {
+ try {
+ String packageName = parser.getAttributeValue(null, KEY_PACKAGE_NAME);
+ AppUriAuthenticationPolicy policy = AppUriAuthenticationPolicy.readFromXml(parser);
+ return new CredentialManagementApp(packageName, policy);
+ } catch (XmlPullParserException | IOException e) {
+ Log.w(TAG, "Reading from xml failed", e);
+ }
+ return null;
+ }
+
+ /**
+ * Save the {@link CredentialManagementApp} to XML.
+ */
+ public void writeToXml(@NonNull XmlSerializer out) throws IOException {
+ out.attribute(null, KEY_PACKAGE_NAME, mPackageName);
+ if (mAuthenticationPolicy != null) {
+ mAuthenticationPolicy.writeToXml(out);
+ }
+ }
+}
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index 9e1fb54bedbe..ae9f866459d6 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -49,6 +49,8 @@ public class Credentials {
public static final String INSTALL_AS_USER_ACTION = "android.credentials.INSTALL_AS_USER";
+ public static final String ACTION_MANAGE_CREDENTIALS = "android.security.MANAGE_CREDENTIALS";
+
/**
* Key prefix for CA certificates.
*
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index 1ae6a631dbcb..f708298a2cbd 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -18,6 +18,8 @@ package android.security;
import android.content.pm.StringParceledListSlice;
import android.security.keymaster.KeymasterCertificateChain;
import android.security.keystore.ParcelableKeyGenParameterSpec;
+import android.security.AppUriAuthenticationPolicy;
+import android.net.Uri;
/**
* Caller is required to ensure that {@link KeyStore#unlock
@@ -47,6 +49,7 @@ interface IKeyChainService {
in byte[] privateKey, in byte[] userCert, in byte[] certChain, String alias, int uid);
boolean removeKeyPair(String alias);
boolean containsKeyPair(String alias);
+ int[] getGrants(String alias);
// APIs used by Settings
boolean deleteCaCertificate(String alias);
@@ -56,6 +59,12 @@ interface IKeyChainService {
boolean containsCaAlias(String alias);
byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem);
List<String> getCaCertificateChainAliases(String rootAlias, boolean includeDeletedSystem);
+ void setCredentialManagementApp(String packageName, in AppUriAuthenticationPolicy policy);
+ boolean hasCredentialManagementApp();
+ String getCredentialManagementAppPackageName();
+ AppUriAuthenticationPolicy getCredentialManagementAppPolicy();
+ String getPredefinedAliasForPackageAndUri(String packageName, in Uri uri);
+ void removeCredentialManagementApp();
// APIs used by KeyChainActivity
void setGrant(int uid, String alias, boolean value);
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 6df62c0a0cba..63690d3c1567 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -15,6 +15,8 @@
*/
package android.security;
+import static android.security.Credentials.ACTION_MANAGE_CREDENTIALS;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SdkConstant;
@@ -122,6 +124,11 @@ public final class KeyChain {
private static final String CERT_INSTALLER_PACKAGE = "com.android.certinstaller";
/**
+ * Package name for Settings.
+ */
+ private static final String SETTINGS_PACKAGE = "com.android.settings";
+
+ /**
* Extra for use with {@link #ACTION_CHOOSER}
* @hide Also used by KeyChainActivity implementation
*/
@@ -202,6 +209,20 @@ public final class KeyChain {
public static final String EXTRA_PKCS12 = "PKCS12";
/**
+ * Extra used by {@link #createManageCredentialsIntent(AppUriAuthenticationPolicy)} to specify
+ * the authentication policy of the credential management app.
+ *
+ * <p>The authentication policy declares which alias for a private key and certificate pair
+ * should be used for authentication, given a list of apps and URIs.
+ *
+ * <p>The extra value should be a {@link AppUriAuthenticationPolicy}.
+ *
+ * @hide
+ */
+ public static final String EXTRA_AUTHENTICATION_POLICY =
+ "android.security.extra.AUTHENTICATION_POLICY";
+
+ /**
* Broadcast Action: Indicates the trusted storage has changed. Sent when
* one of this happens:
*
@@ -386,6 +407,23 @@ public final class KeyChain {
}
/**
+ * Returns an {@code Intent} that should be used by an app to request to manage the user's
+ * credentials. This is limited to unmanaged devices. The authentication policy must be
+ * provided to be able to make this request successfully.
+ *
+ * @param policy The authentication policy determines which alias for a private key and
+ * certificate pair should be used for authentication.
+ */
+ @NonNull
+ public static Intent createManageCredentialsIntent(@NonNull AppUriAuthenticationPolicy policy) {
+ Intent intent = new Intent(ACTION_MANAGE_CREDENTIALS);
+ intent.setComponent(ComponentName.createRelative(SETTINGS_PACKAGE,
+ ".security.RequestManageCredentials"));
+ intent.putExtra(EXTRA_AUTHENTICATION_POLICY, policy);
+ return intent;
+ }
+
+ /**
* Launches an {@code Activity} for the user to select the alias
* for a private key and certificate pair for authentication. The
* selected alias or null will be returned via the
diff --git a/keystore/java/android/security/UrisToAliases.java b/keystore/java/android/security/UrisToAliases.java
new file mode 100644
index 000000000000..65d433abe166
--- /dev/null
+++ b/keystore/java/android/security/UrisToAliases.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlSerializer;
+
+import java.io.IOException;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * The mapping from URI to alias, which determines the alias to use when the user visits a URI.
+ * This mapping is part of the {@link AppUriAuthenticationPolicy}, which specifies which app this
+ * mapping should be used for.
+ *
+ * @hide
+ * @see AppUriAuthenticationPolicy
+ */
+public final class UrisToAliases implements Parcelable {
+
+ private static final String KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS =
+ "authentication_policy_uri_to_alias";
+ private static final String KEY_AUTHENTICATION_POLICY_URI = "policy_uri";
+ private static final String KEY_AUTHENTICATION_POLICY_ALIAS = "policy_alias";
+
+ /**
+ * The mappings from URIs to aliases, which will be used for authentication.
+ */
+ @NonNull
+ private final Map<Uri, String> mUrisToAliases;
+
+ public UrisToAliases() {
+ this.mUrisToAliases = new HashMap<>();
+ }
+
+ private UrisToAliases(@NonNull Map<Uri, String> urisToAliases) {
+ this.mUrisToAliases = urisToAliases;
+ }
+
+ @NonNull
+ public static final Creator<UrisToAliases> CREATOR = new Creator<UrisToAliases>() {
+ @Override
+ public UrisToAliases createFromParcel(Parcel in) {
+ Map<Uri, String> urisToAliases = new HashMap<>();
+ in.readMap(urisToAliases, String.class.getClassLoader());
+ return new UrisToAliases(urisToAliases);
+ }
+
+ @Override
+ public UrisToAliases[] newArray(int size) {
+ return new UrisToAliases[size];
+ }
+ };
+
+ /**
+ * Returns the mapping from URIs to aliases.
+ */
+ @NonNull
+ public Map<Uri, String> getUrisToAliases() {
+ return Collections.unmodifiableMap(mUrisToAliases);
+ }
+
+ /**
+ * Adds mapping from an URI to an alias.
+ */
+ public void addUriToAlias(@NonNull Uri uri, @NonNull String alias) {
+ mUrisToAliases.put(uri, alias);
+ }
+
+ /**
+ * Restore a previously saved {@link UrisToAliases} from XML.
+ */
+ @Nullable
+ public static UrisToAliases readFromXml(@NonNull XmlPullParser parser)
+ throws IOException, XmlPullParserException {
+ Map<Uri, String> urisToAliases = new HashMap<>();
+ int outerDepth = parser.getDepth();
+ int type;
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ if (!parser.getName().equals(KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS)) {
+ continue;
+ }
+ Uri uri = Uri.parse(parser.getAttributeValue(null, KEY_AUTHENTICATION_POLICY_URI));
+ String alias = parser.getAttributeValue(null, KEY_AUTHENTICATION_POLICY_ALIAS);
+ urisToAliases.put(uri, alias);
+ }
+ return new UrisToAliases(urisToAliases);
+ }
+
+ /**
+ * Save the {@link UrisToAliases} to XML.
+ */
+ public void writeToXml(@NonNull XmlSerializer out) throws IOException {
+ for (Map.Entry<Uri, String> urisToAliases : mUrisToAliases.entrySet()) {
+ out.startTag(null, KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS);
+ out.attribute(null, KEY_AUTHENTICATION_POLICY_URI, urisToAliases.getKey().toString());
+ out.attribute(null, KEY_AUTHENTICATION_POLICY_ALIAS, urisToAliases.getValue());
+ out.endTag(null, KEY_AUTHENTICATION_POLICY_URI_TO_ALIAS);
+ }
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeMap(mUrisToAliases);
+ }
+}
diff --git a/keystore/tests/Android.bp b/keystore/tests/Android.bp
index e9b22c140742..2315a8568c64 100644
--- a/keystore/tests/Android.bp
+++ b/keystore/tests/Android.bp
@@ -12,6 +12,15 @@
// See the License for the specific language governing permissions and
// limitations under the License.
+package {
+ // See: http://go/android-license-faq
+ // A large-scale-change added 'default_applicable_licenses' to import
+ // all of the 'license_kinds' from "frameworks_base_keystore_license"
+ // to get the below license kinds:
+ // SPDX-license-identifier-Apache-2.0
+ default_applicable_licenses: ["frameworks_base_keystore_license"],
+}
+
android_test {
name: "KeystoreTests",
// LOCAL_MODULE := keystore