blob: 0660f93e9f016700cc5d06112bc6f6bcf40f7c32 [file] [log] [blame]
Omer Nebil Yaveroglu15395f52020-01-22 12:14:44 +00001/*
2 * Copyright (C) 2019 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
17package android.content.integrity;
18
19import android.annotation.IntDef;
20import android.annotation.NonNull;
21import android.annotation.SystemApi;
22import android.content.integrity.AtomicFormula.BooleanAtomicFormula;
23import android.content.integrity.AtomicFormula.LongAtomicFormula;
24import android.content.integrity.AtomicFormula.StringAtomicFormula;
25import android.os.Parcel;
26import android.os.Parcelable;
27
28import com.android.internal.annotations.VisibleForTesting;
29
30import java.lang.annotation.Retention;
31import java.lang.annotation.RetentionPolicy;
32import java.util.Arrays;
33
34/**
35 * Represents a rule logic/content.
36 *
37 * @hide
38 */
39@SystemApi
40@VisibleForTesting
41public abstract class IntegrityFormula {
42
43 /**
44 * A static formula base for package name formulas.
45 *
46 * This formulation is incomplete and should always be used with {@code equals} formulation.
47 * Evaluates to false when used directly and cannot be written as a parcel.
48 */
49 @NonNull
50 public static final IntegrityFormula PACKAGE_NAME =
51 new StringAtomicFormula(AtomicFormula.PACKAGE_NAME);
52
53 /**
54 * A static formula base for app certificate formulas.
55 *
56 * This formulation is incomplete and should always be used with {@code equals} formulation.
57 * Evaluates to false when used directly and cannot be written as a parcel.
58 */
59 @NonNull
60 public static final IntegrityFormula APP_CERTIFICATE =
61 new StringAtomicFormula(AtomicFormula.APP_CERTIFICATE);
62
63 /**
64 * A static formula base for installer name formulas.
65 *
66 * This formulation is incomplete and should always be used with {@code equals} formulation.
67 * Evaluates to false when used directly and cannot be written as a parcel.
68 */
69 @NonNull
70 public static final IntegrityFormula INSTALLER_NAME =
71 new StringAtomicFormula(AtomicFormula.INSTALLER_NAME);
72
73 /**
74 * A static formula base for installer certificate formulas.
75 *
76 * This formulation is incomplete and should always be used with {@code equals} formulation.
77 * Evaluates to false when used directly and cannot be written as a parcel.
78 */
79 @NonNull
80 public static final IntegrityFormula INSTALLER_CERTIFICATE =
81 new StringAtomicFormula(AtomicFormula.INSTALLER_CERTIFICATE);
82
83 /**
84 * A static formula base for version code name formulas.
85 *
86 * This formulation is incomplete and should always be used with {@code equals},
87 * {@code greaterThan} and {@code greaterThanEquals} formulation. Evaluates to false when used
88 * directly and cannot be written as a parcel.
89 */
90 @NonNull
91 public static final IntegrityFormula VERSION_CODE =
92 new LongAtomicFormula(AtomicFormula.VERSION_CODE);
93
94 /**
95 * A static formula base for pre-installed status formulas.
96 *
97 * This formulation is incomplete and should always be used with {@code equals} formulation.
98 * Evaluates to false when used directly and cannot be written as a parcel.
99 */
100 @NonNull
101 public static final IntegrityFormula PRE_INSTALLED =
102 new BooleanAtomicFormula(AtomicFormula.PRE_INSTALLED);
103
104 /** @hide */
105 @IntDef(
106 value = {
107 COMPOUND_FORMULA_TAG,
108 STRING_ATOMIC_FORMULA_TAG,
109 LONG_ATOMIC_FORMULA_TAG,
110 BOOLEAN_ATOMIC_FORMULA_TAG
111 })
112 @Retention(RetentionPolicy.SOURCE)
113 @interface Tag {}
114
115 /** @hide */
116 public static final int COMPOUND_FORMULA_TAG = 0;
117 /** @hide */
118 public static final int STRING_ATOMIC_FORMULA_TAG = 1;
119 /** @hide */
120 public static final int LONG_ATOMIC_FORMULA_TAG = 2;
121 /** @hide */
122 public static final int BOOLEAN_ATOMIC_FORMULA_TAG = 3;
123
124 /**
125 * Returns the tag that identifies the current class.
126 *
127 * @hide
128 */
129 public abstract @Tag int getTag();
130
131 /**
132 * Returns true when the integrity formula is satisfied by the {@code appInstallMetadata}.
133 *
134 * @hide
135 */
136 public abstract @Tag boolean matches(AppInstallMetadata appInstallMetadata);
137
138 /**
139 * Write an {@link IntegrityFormula} to {@link android.os.Parcel}.
140 *
141 * <p>This helper method is needed because non-final class/interface are not allowed to be
142 * {@link Parcelable}.
143 *
144 * @throws IllegalArgumentException if {@link IntegrityFormula} is not a recognized subclass
145 *
146 * @hide
147 */
148 public static void writeToParcel(
149 @NonNull IntegrityFormula formula, @NonNull Parcel dest, int flags) {
150 dest.writeInt(formula.getTag());
151 ((Parcelable) formula).writeToParcel(dest, flags);
152 }
153
154 /**
155 * Read a {@link IntegrityFormula} from a {@link android.os.Parcel}.
156 *
157 * <p>We need this (hacky) helper method because non-final class/interface cannot be {@link
158 * Parcelable} (api lint error).
159 *
160 * @throws IllegalArgumentException if the parcel cannot be parsed
161 * @hide
162 */
163 @NonNull
164 public static IntegrityFormula readFromParcel(@NonNull Parcel in) {
165 int tag = in.readInt();
166 switch (tag) {
167 case COMPOUND_FORMULA_TAG:
168 return CompoundFormula.CREATOR.createFromParcel(in);
169 case STRING_ATOMIC_FORMULA_TAG:
170 return StringAtomicFormula.CREATOR.createFromParcel(in);
171 case LONG_ATOMIC_FORMULA_TAG:
172 return LongAtomicFormula.CREATOR.createFromParcel(in);
173 case BOOLEAN_ATOMIC_FORMULA_TAG:
174 return BooleanAtomicFormula.CREATOR.createFromParcel(in);
175 default:
176 throw new IllegalArgumentException("Unknown formula tag " + tag);
177 }
178 }
179
180 /**
181 * Returns an integrity formula that evaluates to true when value of the key matches to the
182 * provided string value.
183 *
184 * <p>The value will be hashed with SHA256 and the hex digest will be computed; for
185 * all cases except when the key is PACKAGE_NAME or INSTALLER_NAME and the value is less than
186 * 32 characters.
187 *
188 * <p>Throws an {@link IllegalArgumentException} if the key is not string typed.
189 */
190 @NonNull
191 public IntegrityFormula equalTo(@NonNull String value) {
192 AtomicFormula baseFormula = (AtomicFormula) this;
193 return new AtomicFormula.StringAtomicFormula(baseFormula.getKey(), value);
194 }
195
196 /**
197 * Returns an integrity formula that evaluates to true when the boolean value of the key matches
198 * the provided boolean value. It can only be used with the boolean comparison keys.
199 *
200 * <p>Throws an {@link IllegalArgumentException} if the key is not boolean typed.
201 */
202 @NonNull
203 public IntegrityFormula equalTo(boolean value) {
204 AtomicFormula baseFormula = (AtomicFormula) this;
205 return new AtomicFormula.BooleanAtomicFormula(baseFormula.getKey(), value);
206 }
207
208 /**
209 * Returns a formula that evaluates to true when the value of the key in the package being
210 * installed is equal to {@code value}.
211 *
212 * <p>Throws an {@link IllegalArgumentException} if the key is not long typed.
213 */
214 @NonNull
215 public IntegrityFormula equalTo(long value) {
216 AtomicFormula baseFormula = (AtomicFormula) this;
217 return new AtomicFormula.LongAtomicFormula(baseFormula.getKey(), AtomicFormula.EQ, value);
218 }
219
220 /**
221 * Returns a formula that evaluates to true when the value of the key in the package being
222 * installed is greater than {@code value}.
223 *
224 * <p>Throws an {@link IllegalArgumentException} if the key is not long typed.
225 */
226 @NonNull
227 public IntegrityFormula greaterThan(long value) {
228 AtomicFormula baseFormula = (AtomicFormula) this;
229 return new AtomicFormula.LongAtomicFormula(baseFormula.getKey(), AtomicFormula.GT, value);
230 }
231
232 /**
233 * Returns a formula that evaluates to true when the value of the key in the package being
234 * installed is greater than or equals to the {@code value}.
235 *
236 * <p>Throws an {@link IllegalArgumentException} if the key is not long typed.
237 */
238 @NonNull
239 public IntegrityFormula greaterThanOrEquals(long value) {
240 AtomicFormula baseFormula = (AtomicFormula) this;
241 return new AtomicFormula.LongAtomicFormula(baseFormula.getKey(), AtomicFormula.GTE, value);
242 }
243
244 /**
245 * Returns a formula that evaluates to true when any formula in {@code formulae} evaluates to
246 * true.
247 *
248 * <p>Throws an {@link IllegalArgumentException} if formulae has less than two elements.
249 */
250 @NonNull
251 public static IntegrityFormula any(@NonNull IntegrityFormula... formulae) {
252 return new CompoundFormula(CompoundFormula.OR, Arrays.asList(formulae));
253 }
254
255 /**
256 * Returns a formula that evaluates to true when all formula in {@code formulae} evaluates to
257 * true.
258 *
259 * <p>Throws an {@link IllegalArgumentException} if formulae has less than two elements.
260 */
261 @NonNull
262 public static IntegrityFormula all(@NonNull IntegrityFormula... formulae) {
263 return new CompoundFormula(CompoundFormula.AND, Arrays.asList(formulae));
264 }
265
266 /**
267 * Returns a formula that evaluates to true when {@code formula} evaluates to false.
268 */
269 @NonNull
270 public static IntegrityFormula not(@NonNull IntegrityFormula formula) {
271 return new CompoundFormula(CompoundFormula.NOT, Arrays.asList(formula));
272 }
273
274 // Constructor is package private so it cannot be inherited outside of this package.
275 IntegrityFormula() {
276 }
277}