1 /*
2  * Copyright (C) 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.content.integrity;
18 
19 import android.annotation.NonNull;
20 
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24 import java.util.Objects;
25 
26 /**
27  * The app install metadata.
28  *
29  * <p>The integrity component retrieves metadata for app installs from package manager, passing it
30  * to the rule evaluation engine to evaluate the metadata against the rules.
31  *
32  * <p>Instances of this class are immutable.
33  *
34  * @hide
35  */
36 public final class AppInstallMetadata {
37     private final String mPackageName;
38     // Raw string encoding for the SHA-256 hash of the certificate of the app.
39     private final List<String> mAppCertificates;
40     // Raw string encoding for the SHA-256 hash of the certificate lineage/history of the app.
41     private final List<String> mAppCertificateLineage;
42     private final String mInstallerName;
43     // Raw string encoding for the SHA-256 hash of the certificate of the installer.
44     private final List<String> mInstallerCertificates;
45     private final long mVersionCode;
46     private final boolean mIsPreInstalled;
47     private final boolean mIsStampPresent;
48     private final boolean mIsStampVerified;
49     private final boolean mIsStampTrusted;
50     // Raw string encoding for the SHA-256 hash of the certificate of the stamp.
51     private final String mStampCertificateHash;
52     private final Map<String, String> mAllowedInstallersAndCertificates;
53 
AppInstallMetadata(Builder builder)54     private AppInstallMetadata(Builder builder) {
55         this.mPackageName = builder.mPackageName;
56         this.mAppCertificates = builder.mAppCertificates;
57         this.mAppCertificateLineage = builder.mAppCertificateLineage;
58         this.mInstallerName = builder.mInstallerName;
59         this.mInstallerCertificates = builder.mInstallerCertificates;
60         this.mVersionCode = builder.mVersionCode;
61         this.mIsPreInstalled = builder.mIsPreInstalled;
62         this.mIsStampPresent = builder.mIsStampPresent;
63         this.mIsStampVerified = builder.mIsStampVerified;
64         this.mIsStampTrusted = builder.mIsStampTrusted;
65         this.mStampCertificateHash = builder.mStampCertificateHash;
66         this.mAllowedInstallersAndCertificates = builder.mAllowedInstallersAndCertificates;
67     }
68 
69     @NonNull
getPackageName()70     public String getPackageName() {
71         return mPackageName;
72     }
73 
74     @NonNull
getAppCertificates()75     public List<String> getAppCertificates() {
76         return mAppCertificates;
77     }
78 
79     @NonNull
getAppCertificateLineage()80     public List<String> getAppCertificateLineage() {
81         return mAppCertificateLineage;
82     }
83 
84     @NonNull
getInstallerName()85     public String getInstallerName() {
86         return mInstallerName;
87     }
88 
89     @NonNull
getInstallerCertificates()90     public List<String> getInstallerCertificates() {
91         return mInstallerCertificates;
92     }
93 
94     /** @see AppInstallMetadata.Builder#setVersionCode(long) */
getVersionCode()95     public long getVersionCode() {
96         return mVersionCode;
97     }
98 
99     /** @see AppInstallMetadata.Builder#setIsPreInstalled(boolean) */
isPreInstalled()100     public boolean isPreInstalled() {
101         return mIsPreInstalled;
102     }
103 
104     /** @see AppInstallMetadata.Builder#setIsStampPresent(boolean) */
isStampPresent()105     public boolean isStampPresent() {
106         return mIsStampPresent;
107     }
108 
109     /** @see AppInstallMetadata.Builder#setIsStampVerified(boolean) */
isStampVerified()110     public boolean isStampVerified() {
111         return mIsStampVerified;
112     }
113 
114     /** @see AppInstallMetadata.Builder#setIsStampTrusted(boolean) */
isStampTrusted()115     public boolean isStampTrusted() {
116         return mIsStampTrusted;
117     }
118 
119     /** @see AppInstallMetadata.Builder#setStampCertificateHash(String) */
getStampCertificateHash()120     public String getStampCertificateHash() {
121         return mStampCertificateHash;
122     }
123 
124     /** Get the allowed installers and their corresponding cert. */
getAllowedInstallersAndCertificates()125     public Map<String, String> getAllowedInstallersAndCertificates() {
126         return mAllowedInstallersAndCertificates;
127     }
128 
129     @Override
toString()130     public String toString() {
131         return String.format(
132                 "AppInstallMetadata {"
133                     + " PackageName = %s,"
134                     + " AppCerts = %s,"
135                     + " AppCertsLineage = %s,"
136                     + " InstallerName = %s,"
137                     + " InstallerCerts = %s,"
138                     + " VersionCode = %d,"
139                     + " PreInstalled = %b,"
140                     + " StampPresent = %b,"
141                     + " StampVerified = %b,"
142                     + " StampTrusted = %b,"
143                     + " StampCert = %s }",
144                 mPackageName,
145                 mAppCertificates,
146                 mAppCertificateLineage,
147                 mInstallerName == null ? "null" : mInstallerName,
148                 mInstallerCertificates == null ? "null" : mInstallerCertificates,
149                 mVersionCode,
150                 mIsPreInstalled,
151                 mIsStampPresent,
152                 mIsStampVerified,
153                 mIsStampTrusted,
154                 mStampCertificateHash == null ? "null" : mStampCertificateHash);
155     }
156 
157     /** Builder class for constructing {@link AppInstallMetadata} objects. */
158     public static final class Builder {
159         private String mPackageName;
160         private List<String> mAppCertificates;
161         private List<String> mAppCertificateLineage;
162         private String mInstallerName;
163         private List<String> mInstallerCertificates;
164         private long mVersionCode;
165         private boolean mIsPreInstalled;
166         private boolean mIsStampPresent;
167         private boolean mIsStampVerified;
168         private boolean mIsStampTrusted;
169         private String mStampCertificateHash;
170         private Map<String, String> mAllowedInstallersAndCertificates;
171 
Builder()172         public Builder() {
173             mAllowedInstallersAndCertificates = new HashMap<>();
174         }
175 
176         /**
177          * Add allowed installers and cert.
178          *
179          * @see AppInstallMetadata#getAllowedInstallersAndCertificates()
180          */
181         @NonNull
setAllowedInstallersAndCert( @onNull Map<String, String> allowedInstallersAndCertificates)182         public Builder setAllowedInstallersAndCert(
183                 @NonNull Map<String, String> allowedInstallersAndCertificates) {
184             this.mAllowedInstallersAndCertificates = allowedInstallersAndCertificates;
185             return this;
186         }
187 
188         /**
189          * Set package name of the app to be installed.
190          *
191          * @see AppInstallMetadata#getPackageName()
192          */
193         @NonNull
setPackageName(@onNull String packageName)194         public Builder setPackageName(@NonNull String packageName) {
195             this.mPackageName = Objects.requireNonNull(packageName);
196             return this;
197         }
198 
199         /**
200          * Set certificate of the app to be installed.
201          *
202          * <p>It is represented as the raw string encoding for the SHA-256 hash of the certificate
203          * of the app.
204          *
205          * @see AppInstallMetadata#getAppCertificates()
206          */
207         @NonNull
setAppCertificates(@onNull List<String> appCertificates)208         public Builder setAppCertificates(@NonNull List<String> appCertificates) {
209             this.mAppCertificates = Objects.requireNonNull(appCertificates);
210             return this;
211         }
212 
213         /**
214          * Set the list of (old and new) certificates used for signing the app to be installed.
215          *
216          * <p>It is represented as the raw string encoding for the SHA-256 hash of the certificate
217          * lineage/history of the app.
218          *
219          * @see AppInstallMetadata#getAppCertificateLineage()
220          */
221         @NonNull
setAppCertificateLineage(@onNull List<String> appCertificateLineage)222         public Builder setAppCertificateLineage(@NonNull List<String> appCertificateLineage) {
223             this.mAppCertificateLineage = Objects.requireNonNull(appCertificateLineage);
224             return this;
225         }
226 
227         /**
228          * Set name of the installer installing the app.
229          *
230          * @see AppInstallMetadata#getInstallerName()
231          */
232         @NonNull
setInstallerName(@onNull String installerName)233         public Builder setInstallerName(@NonNull String installerName) {
234             this.mInstallerName = Objects.requireNonNull(installerName);
235             return this;
236         }
237 
238         /**
239          * Set certificate of the installer installing the app.
240          *
241          * <p>It is represented as the raw string encoding for the SHA-256 hash of the certificate
242          * of the installer.
243          *
244          * @see AppInstallMetadata#getInstallerCertificates()
245          */
246         @NonNull
setInstallerCertificates(@onNull List<String> installerCertificates)247         public Builder setInstallerCertificates(@NonNull List<String> installerCertificates) {
248             this.mInstallerCertificates = Objects.requireNonNull(installerCertificates);
249             return this;
250         }
251 
252         /**
253          * Set version code of the app to be installed.
254          *
255          * @see AppInstallMetadata#getVersionCode()
256          */
257         @NonNull
setVersionCode(long versionCode)258         public Builder setVersionCode(long versionCode) {
259             this.mVersionCode = versionCode;
260             return this;
261         }
262 
263         /**
264          * Set whether the app is pre-installed on the device or not.
265          *
266          * @see AppInstallMetadata#isPreInstalled()
267          */
268         @NonNull
setIsPreInstalled(boolean isPreInstalled)269         public Builder setIsPreInstalled(boolean isPreInstalled) {
270             this.mIsPreInstalled = isPreInstalled;
271             return this;
272         }
273 
274         /**
275          * Set whether the stamp embedded in the APK is present or not.
276          *
277          * @see AppInstallMetadata#isStampPresent()
278          */
279         @NonNull
setIsStampPresent(boolean isStampPresent)280         public Builder setIsStampPresent(boolean isStampPresent) {
281             this.mIsStampPresent = isStampPresent;
282             return this;
283         }
284 
285         /**
286          * Set whether the stamp embedded in the APK is verified or not.
287          *
288          * @see AppInstallMetadata#isStampVerified()
289          */
290         @NonNull
setIsStampVerified(boolean isStampVerified)291         public Builder setIsStampVerified(boolean isStampVerified) {
292             this.mIsStampVerified = isStampVerified;
293             return this;
294         }
295 
296         /**
297          * Set whether the stamp embedded in the APK is trusted or not.
298          *
299          * @see AppInstallMetadata#isStampTrusted()
300          */
301         @NonNull
setIsStampTrusted(boolean isStampTrusted)302         public Builder setIsStampTrusted(boolean isStampTrusted) {
303             this.mIsStampTrusted = isStampTrusted;
304             return this;
305         }
306 
307         /**
308          * Set certificate hash of the stamp embedded in the APK.
309          *
310          * <p>It is represented as the raw string encoding for the SHA-256 hash of the certificate
311          * of the stamp.
312          *
313          * @see AppInstallMetadata#getStampCertificateHash()
314          */
315         @NonNull
setStampCertificateHash(@onNull String stampCertificateHash)316         public Builder setStampCertificateHash(@NonNull String stampCertificateHash) {
317             this.mStampCertificateHash = Objects.requireNonNull(stampCertificateHash);
318             return this;
319         }
320 
321         /**
322          * Build {@link AppInstallMetadata}.
323          *
324          * @throws IllegalArgumentException if package name or app certificate is null
325          */
326         @NonNull
build()327         public AppInstallMetadata build() {
328             Objects.requireNonNull(mPackageName);
329             Objects.requireNonNull(mAppCertificates);
330             Objects.requireNonNull(mAppCertificateLineage);
331             return new AppInstallMetadata(this);
332         }
333     }
334 }
335