/* * 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.content.integrity; import android.annotation.NonNull; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Objects; /** * The app install metadata. * *

The integrity component retrieves metadata for app installs from package manager, passing it * to the rule evaluation engine to evaluate the metadata against the rules. * *

Instances of this class are immutable. * * @hide */ public final class AppInstallMetadata { private final String mPackageName; // Raw string encoding for the SHA-256 hash of the certificate of the app. private final List mAppCertificates; // Raw string encoding for the SHA-256 hash of the certificate lineage/history of the app. private final List mAppCertificateLineage; private final String mInstallerName; // Raw string encoding for the SHA-256 hash of the certificate of the installer. private final List mInstallerCertificates; private final long mVersionCode; private final boolean mIsPreInstalled; private final boolean mIsStampPresent; private final boolean mIsStampVerified; private final boolean mIsStampTrusted; // Raw string encoding for the SHA-256 hash of the certificate of the stamp. private final String mStampCertificateHash; private final Map mAllowedInstallersAndCertificates; private AppInstallMetadata(Builder builder) { this.mPackageName = builder.mPackageName; this.mAppCertificates = builder.mAppCertificates; this.mAppCertificateLineage = builder.mAppCertificateLineage; this.mInstallerName = builder.mInstallerName; this.mInstallerCertificates = builder.mInstallerCertificates; this.mVersionCode = builder.mVersionCode; this.mIsPreInstalled = builder.mIsPreInstalled; this.mIsStampPresent = builder.mIsStampPresent; this.mIsStampVerified = builder.mIsStampVerified; this.mIsStampTrusted = builder.mIsStampTrusted; this.mStampCertificateHash = builder.mStampCertificateHash; this.mAllowedInstallersAndCertificates = builder.mAllowedInstallersAndCertificates; } @NonNull public String getPackageName() { return mPackageName; } @NonNull public List getAppCertificates() { return mAppCertificates; } @NonNull public List getAppCertificateLineage() { return mAppCertificateLineage; } @NonNull public String getInstallerName() { return mInstallerName; } @NonNull public List getInstallerCertificates() { return mInstallerCertificates; } /** @see AppInstallMetadata.Builder#setVersionCode(long) */ public long getVersionCode() { return mVersionCode; } /** @see AppInstallMetadata.Builder#setIsPreInstalled(boolean) */ public boolean isPreInstalled() { return mIsPreInstalled; } /** @see AppInstallMetadata.Builder#setIsStampPresent(boolean) */ public boolean isStampPresent() { return mIsStampPresent; } /** @see AppInstallMetadata.Builder#setIsStampVerified(boolean) */ public boolean isStampVerified() { return mIsStampVerified; } /** @see AppInstallMetadata.Builder#setIsStampTrusted(boolean) */ public boolean isStampTrusted() { return mIsStampTrusted; } /** @see AppInstallMetadata.Builder#setStampCertificateHash(String) */ public String getStampCertificateHash() { return mStampCertificateHash; } /** Get the allowed installers and their corresponding cert. */ public Map getAllowedInstallersAndCertificates() { return mAllowedInstallersAndCertificates; } @Override public String toString() { return String.format( "AppInstallMetadata {" + " PackageName = %s," + " AppCerts = %s," + " AppCertsLineage = %s," + " InstallerName = %s," + " InstallerCerts = %s," + " VersionCode = %d," + " PreInstalled = %b," + " StampPresent = %b," + " StampVerified = %b," + " StampTrusted = %b," + " StampCert = %s }", mPackageName, mAppCertificates, mAppCertificateLineage, mInstallerName == null ? "null" : mInstallerName, mInstallerCertificates == null ? "null" : mInstallerCertificates, mVersionCode, mIsPreInstalled, mIsStampPresent, mIsStampVerified, mIsStampTrusted, mStampCertificateHash == null ? "null" : mStampCertificateHash); } /** Builder class for constructing {@link AppInstallMetadata} objects. */ public static final class Builder { private String mPackageName; private List mAppCertificates; private List mAppCertificateLineage; private String mInstallerName; private List mInstallerCertificates; private long mVersionCode; private boolean mIsPreInstalled; private boolean mIsStampPresent; private boolean mIsStampVerified; private boolean mIsStampTrusted; private String mStampCertificateHash; private Map mAllowedInstallersAndCertificates; public Builder() { mAllowedInstallersAndCertificates = new HashMap<>(); } /** * Add allowed installers and cert. * * @see AppInstallMetadata#getAllowedInstallersAndCertificates() */ @NonNull public Builder setAllowedInstallersAndCert( @NonNull Map allowedInstallersAndCertificates) { this.mAllowedInstallersAndCertificates = allowedInstallersAndCertificates; return this; } /** * Set package name of the app to be installed. * * @see AppInstallMetadata#getPackageName() */ @NonNull public Builder setPackageName(@NonNull String packageName) { this.mPackageName = Objects.requireNonNull(packageName); return this; } /** * Set certificate of the app to be installed. * *

It is represented as the raw string encoding for the SHA-256 hash of the certificate * of the app. * * @see AppInstallMetadata#getAppCertificates() */ @NonNull public Builder setAppCertificates(@NonNull List appCertificates) { this.mAppCertificates = Objects.requireNonNull(appCertificates); return this; } /** * Set the list of (old and new) certificates used for signing the app to be installed. * *

It is represented as the raw string encoding for the SHA-256 hash of the certificate * lineage/history of the app. * * @see AppInstallMetadata#getAppCertificateLineage() */ @NonNull public Builder setAppCertificateLineage(@NonNull List appCertificateLineage) { this.mAppCertificateLineage = Objects.requireNonNull(appCertificateLineage); return this; } /** * Set name of the installer installing the app. * * @see AppInstallMetadata#getInstallerName() */ @NonNull public Builder setInstallerName(@NonNull String installerName) { this.mInstallerName = Objects.requireNonNull(installerName); return this; } /** * Set certificate of the installer installing the app. * *

It is represented as the raw string encoding for the SHA-256 hash of the certificate * of the installer. * * @see AppInstallMetadata#getInstallerCertificates() */ @NonNull public Builder setInstallerCertificates(@NonNull List installerCertificates) { this.mInstallerCertificates = Objects.requireNonNull(installerCertificates); return this; } /** * Set version code of the app to be installed. * * @see AppInstallMetadata#getVersionCode() */ @NonNull public Builder setVersionCode(long versionCode) { this.mVersionCode = versionCode; return this; } /** * Set whether the app is pre-installed on the device or not. * * @see AppInstallMetadata#isPreInstalled() */ @NonNull public Builder setIsPreInstalled(boolean isPreInstalled) { this.mIsPreInstalled = isPreInstalled; return this; } /** * Set whether the stamp embedded in the APK is present or not. * * @see AppInstallMetadata#isStampPresent() */ @NonNull public Builder setIsStampPresent(boolean isStampPresent) { this.mIsStampPresent = isStampPresent; return this; } /** * Set whether the stamp embedded in the APK is verified or not. * * @see AppInstallMetadata#isStampVerified() */ @NonNull public Builder setIsStampVerified(boolean isStampVerified) { this.mIsStampVerified = isStampVerified; return this; } /** * Set whether the stamp embedded in the APK is trusted or not. * * @see AppInstallMetadata#isStampTrusted() */ @NonNull public Builder setIsStampTrusted(boolean isStampTrusted) { this.mIsStampTrusted = isStampTrusted; return this; } /** * Set certificate hash of the stamp embedded in the APK. * *

It is represented as the raw string encoding for the SHA-256 hash of the certificate * of the stamp. * * @see AppInstallMetadata#getStampCertificateHash() */ @NonNull public Builder setStampCertificateHash(@NonNull String stampCertificateHash) { this.mStampCertificateHash = Objects.requireNonNull(stampCertificateHash); return this; } /** * Build {@link AppInstallMetadata}. * * @throws IllegalArgumentException if package name or app certificate is null */ @NonNull public AppInstallMetadata build() { Objects.requireNonNull(mPackageName); Objects.requireNonNull(mAppCertificates); Objects.requireNonNull(mAppCertificateLineage); return new AppInstallMetadata(this); } } }