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

Commit e5ba22ab authored by Rubin Xu's avatar Rubin Xu Committed by Automerger Merge Worker
Browse files

Merge "Add KeyChainService credential management app APIs" am: e02debeb

Original change: https://android-review.googlesource.com/c/platform/frameworks/base/+/1549395

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Id023e84b28ec938a90fe9a78bc985f12a0031609
parents 190bdb19 e02debeb
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -35970,6 +35970,19 @@ package android.se.omapi {
package android.security {
  public final class AppUriAuthenticationPolicy implements android.os.Parcelable {
    method public int describeContents();
    method @NonNull public java.util.Map<java.lang.String,java.util.Map<android.net.Uri,java.lang.String>> getAppAndUriMappings();
    method public void writeToParcel(@NonNull android.os.Parcel, int);
    field @NonNull public static final android.os.Parcelable.Creator<android.security.AppUriAuthenticationPolicy> CREATOR;
  }
  public static final class AppUriAuthenticationPolicy.Builder {
    ctor public AppUriAuthenticationPolicy.Builder();
    method @NonNull public android.security.AppUriAuthenticationPolicy.Builder addAppAndUriMapping(@NonNull String, @NonNull android.net.Uri, @NonNull String);
    method @NonNull public android.security.AppUriAuthenticationPolicy build();
  }
  public final class AttestedKeyPair {
    ctor public AttestedKeyPair(@Nullable java.security.KeyPair, @NonNull java.util.List<java.security.cert.Certificate>);
    method @NonNull public java.util.List<java.security.cert.Certificate> getAttestationRecord();
+19 −0
Original line number Diff line number Diff line
/*
 * 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;
+241 −0
Original line number Diff line number Diff line
/*
 * 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;
    }

}
+123 −0
Original line number Diff line number Diff line
/*
 * 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);
        }
    }
}
+9 −0
Original line number Diff line number Diff line
@@ -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
@@ -56,6 +58,13 @@ 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);
    void updateCredentialManagementAppPolicy(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);
Loading