blob: ab67d372021ba251d77ec81179066e41a808cba2 [file] [log] [blame]
Dan Cashmane92f8422017-12-08 14:02:51 -08001/*
2 * Copyright (C) 2017 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.util.apk;
18
19import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST;
20import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
21import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
22import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES;
23import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
24import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER;
25
26import android.content.pm.PackageParser;
27import android.content.pm.PackageParser.PackageParserException;
Patrick Baumann420d58a2017-12-19 10:17:21 -080028import android.content.pm.PackageParser.SigningDetails.SignatureSchemeVersion;
Dan Cashmane92f8422017-12-08 14:02:51 -080029import android.content.pm.Signature;
30import android.os.Trace;
31import android.util.jar.StrictJarFile;
32
33import com.android.internal.util.ArrayUtils;
34
35import libcore.io.IoUtils;
36
37import java.io.IOException;
38import java.io.InputStream;
Victor Hsieh07bc80c2018-01-11 16:15:47 -080039import java.security.DigestException;
Dan Cashmane92f8422017-12-08 14:02:51 -080040import java.security.GeneralSecurityException;
Victor Hsieh07bc80c2018-01-11 16:15:47 -080041import java.security.NoSuchAlgorithmException;
Dan Cashmane92f8422017-12-08 14:02:51 -080042import java.security.cert.Certificate;
43import java.security.cert.CertificateEncodingException;
44import java.util.ArrayList;
45import java.util.Iterator;
46import java.util.List;
47import java.util.concurrent.atomic.AtomicReference;
48import java.util.zip.ZipEntry;
49
50/**
51 * Facade class that takes care of the details of APK verification on
52 * behalf of PackageParser.
53 *
54 * @hide for internal use only.
55 */
56public class ApkSignatureVerifier {
57
Dan Cashmane92f8422017-12-08 14:02:51 -080058 private static final AtomicReference<byte[]> sBuffer = new AtomicReference<>();
59
60 /**
Dan Cashman636ea5e2017-12-18 10:38:20 -080061 * Verifies the provided APK and returns the certificates associated with each signer.
Dan Cashmane92f8422017-12-08 14:02:51 -080062 *
63 * @throws PackageParserException if the APK's signature failed to verify.
Dan Cashmane92f8422017-12-08 14:02:51 -080064 */
Patrick Baumann420d58a2017-12-19 10:17:21 -080065 public static PackageParser.SigningDetails verify(String apkPath,
66 @SignatureSchemeVersion int minSignatureSchemeVersion)
Patrick Baumann9ff55742017-12-14 10:50:18 -080067 throws PackageParserException {
Dan Cashmane92f8422017-12-08 14:02:51 -080068
Patrick Baumann420d58a2017-12-19 10:17:21 -080069 if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
Daniel Cashman67096e02017-12-28 12:46:33 -080070 // V3 and before are older than the requested minimum signing version
71 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
72 "No signature found in package of version " + minSignatureSchemeVersion
73 + " or newer for package " + apkPath);
74 }
75
76 // first try v3
77 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV3");
78 try {
79 ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner =
80 ApkSignatureSchemeV3Verifier.verify(apkPath);
81 Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
82 Signature[] signerSigs = convertToSignatures(signerCerts);
Daniel Cashman77029c52018-01-18 16:19:29 -080083 Signature[] pastSignerSigs = null;
Daniel Cashman77029c52018-01-18 16:19:29 -080084 if (vSigner.por != null) {
85 // populate proof-of-rotation information
86 pastSignerSigs = new Signature[vSigner.por.certs.size()];
Daniel Cashman77029c52018-01-18 16:19:29 -080087 for (int i = 0; i < pastSignerSigs.length; i++) {
88 pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded());
Michael Groovera117b0d2018-07-23 12:55:54 -070089 pastSignerSigs[i].setFlags(vSigner.por.flagsList.get(i));
Daniel Cashman77029c52018-01-18 16:19:29 -080090 }
91 }
92 return new PackageParser.SigningDetails(
93 signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3,
Michael Groovera117b0d2018-07-23 12:55:54 -070094 pastSignerSigs);
Daniel Cashman67096e02017-12-28 12:46:33 -080095 } catch (SignatureNotFoundException e) {
Daniel Cashman77029c52018-01-18 16:19:29 -080096 // not signed with v3, try older if allowed
Patrick Baumann420d58a2017-12-19 10:17:21 -080097 if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) {
Daniel Cashman67096e02017-12-28 12:46:33 -080098 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
99 "No APK Signature Scheme v3 signature in package " + apkPath, e);
100 }
101 } catch (Exception e) {
102 // APK Signature Scheme v2 signature found but did not verify
103 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
104 "Failed to collect certificates from " + apkPath
Daniel Cashman77029c52018-01-18 16:19:29 -0800105 + " using APK Signature Scheme v3", e);
Daniel Cashman67096e02017-12-28 12:46:33 -0800106 } finally {
107 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
108 }
109
110 // redundant, protective version check
Patrick Baumann420d58a2017-12-19 10:17:21 -0800111 if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V2) {
Daniel Cashman67096e02017-12-28 12:46:33 -0800112 // V2 and before are older than the requested minimum signing version
113 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
114 "No signature found in package of version " + minSignatureSchemeVersion
115 + " or newer for package " + apkPath);
116 }
117
118 // try v2
Dan Cashmane92f8422017-12-08 14:02:51 -0800119 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "verifyV2");
120 try {
Dan Cashman636ea5e2017-12-18 10:38:20 -0800121 Certificate[][] signerCerts = ApkSignatureSchemeV2Verifier.verify(apkPath);
Dan Cashmane92f8422017-12-08 14:02:51 -0800122 Signature[] signerSigs = convertToSignatures(signerCerts);
123
Patrick Baumann420d58a2017-12-19 10:17:21 -0800124 return new PackageParser.SigningDetails(
125 signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V2);
Dan Cashmane92f8422017-12-08 14:02:51 -0800126 } catch (SignatureNotFoundException e) {
127 // not signed with v2, try older if allowed
Patrick Baumann420d58a2017-12-19 10:17:21 -0800128 if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V2) {
Patrick Baumann9ff55742017-12-14 10:50:18 -0800129 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
130 "No APK Signature Scheme v2 signature in package " + apkPath, e);
Dan Cashmane92f8422017-12-08 14:02:51 -0800131 }
Dan Cashmane92f8422017-12-08 14:02:51 -0800132 } catch (Exception e) {
133 // APK Signature Scheme v2 signature found but did not verify
134 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
135 "Failed to collect certificates from " + apkPath
136 + " using APK Signature Scheme v2", e);
137 } finally {
138 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
139 }
140
Daniel Cashman67096e02017-12-28 12:46:33 -0800141 // redundant, protective version check
Patrick Baumann420d58a2017-12-19 10:17:21 -0800142 if (minSignatureSchemeVersion > SignatureSchemeVersion.JAR) {
Daniel Cashman67096e02017-12-28 12:46:33 -0800143 // V1 and is older than the requested minimum signing version
144 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
145 "No signature found in package of version " + minSignatureSchemeVersion
146 + " or newer for package " + apkPath);
147 }
148
Dan Cashmane92f8422017-12-08 14:02:51 -0800149 // v2 didn't work, try jarsigner
Dan Cashman636ea5e2017-12-18 10:38:20 -0800150 return verifyV1Signature(apkPath, true);
Dan Cashmane92f8422017-12-08 14:02:51 -0800151 }
152
Dan Cashman636ea5e2017-12-18 10:38:20 -0800153 /**
154 * Verifies the provided APK and returns the certificates associated with each signer.
155 *
156 * @param verifyFull whether to verify all contents of this APK or just collect certificates.
157 *
158 * @throws PackageParserException if there was a problem collecting certificates
159 */
Patrick Baumann420d58a2017-12-19 10:17:21 -0800160 private static PackageParser.SigningDetails verifyV1Signature(
161 String apkPath, boolean verifyFull)
Dan Cashmane92f8422017-12-08 14:02:51 -0800162 throws PackageParserException {
163 StrictJarFile jarFile = null;
164
165 try {
166 final Certificate[][] lastCerts;
167 final Signature[] lastSigs;
168
169 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "strictJarFileCtor");
Dan Cashman636ea5e2017-12-18 10:38:20 -0800170
171 // we still pass verify = true to ctor to collect certs, even though we're not checking
172 // the whole jar.
173 jarFile = new StrictJarFile(
174 apkPath,
175 true, // collect certs
176 verifyFull); // whether to reject APK with stripped v2 signatures (b/27887819)
Dan Cashmane92f8422017-12-08 14:02:51 -0800177 final List<ZipEntry> toVerify = new ArrayList<>();
178
Dan Cashman636ea5e2017-12-18 10:38:20 -0800179 // Gather certs from AndroidManifest.xml, which every APK must have, as an optimization
180 // to not need to verify the whole APK when verifyFUll == false.
Dan Cashmane92f8422017-12-08 14:02:51 -0800181 final ZipEntry manifestEntry = jarFile.findEntry(
182 PackageParser.ANDROID_MANIFEST_FILENAME);
183 if (manifestEntry == null) {
184 throw new PackageParserException(INSTALL_PARSE_FAILED_BAD_MANIFEST,
185 "Package " + apkPath + " has no manifest");
186 }
187 lastCerts = loadCertificates(jarFile, manifestEntry);
188 if (ArrayUtils.isEmpty(lastCerts)) {
189 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Package "
190 + apkPath + " has no certificates at entry "
191 + PackageParser.ANDROID_MANIFEST_FILENAME);
192 }
193 lastSigs = convertToSignatures(lastCerts);
194
Dan Cashman636ea5e2017-12-18 10:38:20 -0800195 // fully verify all contents, except for AndroidManifest.xml and the META-INF/ files.
196 if (verifyFull) {
Dan Cashmane92f8422017-12-08 14:02:51 -0800197 final Iterator<ZipEntry> i = jarFile.iterator();
198 while (i.hasNext()) {
199 final ZipEntry entry = i.next();
200 if (entry.isDirectory()) continue;
201
202 final String entryName = entry.getName();
203 if (entryName.startsWith("META-INF/")) continue;
204 if (entryName.equals(PackageParser.ANDROID_MANIFEST_FILENAME)) continue;
205
206 toVerify.add(entry);
207 }
208
Dan Cashmane92f8422017-12-08 14:02:51 -0800209 for (ZipEntry entry : toVerify) {
210 final Certificate[][] entryCerts = loadCertificates(jarFile, entry);
211 if (ArrayUtils.isEmpty(entryCerts)) {
212 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
213 "Package " + apkPath + " has no certificates at entry "
214 + entry.getName());
215 }
216
217 // make sure all entries use the same signing certs
218 final Signature[] entrySigs = convertToSignatures(entryCerts);
219 if (!Signature.areExactMatch(lastSigs, entrySigs)) {
220 throw new PackageParserException(
221 INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES,
222 "Package " + apkPath + " has mismatched certificates at entry "
223 + entry.getName());
224 }
225 }
226 }
Patrick Baumann420d58a2017-12-19 10:17:21 -0800227 return new PackageParser.SigningDetails(lastSigs, SignatureSchemeVersion.JAR);
Dan Cashmane92f8422017-12-08 14:02:51 -0800228 } catch (GeneralSecurityException e) {
229 throw new PackageParserException(INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING,
230 "Failed to collect certificates from " + apkPath, e);
231 } catch (IOException | RuntimeException e) {
232 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
233 "Failed to collect certificates from " + apkPath, e);
234 } finally {
235 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
236 closeQuietly(jarFile);
237 }
238 }
239
240 private static Certificate[][] loadCertificates(StrictJarFile jarFile, ZipEntry entry)
241 throws PackageParserException {
242 InputStream is = null;
243 try {
244 // We must read the stream for the JarEntry to retrieve
245 // its certificates.
246 is = jarFile.getInputStream(entry);
247 readFullyIgnoringContents(is);
248 return jarFile.getCertificateChains(entry);
249 } catch (IOException | RuntimeException e) {
250 throw new PackageParserException(INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION,
251 "Failed reading " + entry.getName() + " in " + jarFile, e);
252 } finally {
253 IoUtils.closeQuietly(is);
254 }
255 }
256
257 private static void readFullyIgnoringContents(InputStream in) throws IOException {
258 byte[] buffer = sBuffer.getAndSet(null);
259 if (buffer == null) {
260 buffer = new byte[4096];
261 }
262
263 int n = 0;
264 int count = 0;
265 while ((n = in.read(buffer, 0, buffer.length)) != -1) {
266 count += n;
267 }
268
269 sBuffer.set(buffer);
270 return;
271 }
272
273 /**
274 * Converts an array of certificate chains into the {@code Signature} equivalent used by the
275 * PackageManager.
276 *
277 * @throws CertificateEncodingException if it is unable to create a Signature object.
278 */
279 public static Signature[] convertToSignatures(Certificate[][] certs)
280 throws CertificateEncodingException {
281 final Signature[] res = new Signature[certs.length];
282 for (int i = 0; i < certs.length; i++) {
283 res[i] = new Signature(certs[i]);
284 }
285 return res;
286 }
287
288 private static void closeQuietly(StrictJarFile jarFile) {
289 if (jarFile != null) {
290 try {
291 jarFile.close();
292 } catch (Exception ignored) {
293 }
294 }
295 }
296
297 /**
Dan Cashman636ea5e2017-12-18 10:38:20 -0800298 * Returns the certificates associated with each signer for the given APK without verification.
299 * This method is dangerous and should not be used, unless the caller is absolutely certain the
300 * APK is trusted.
301 *
302 * @throws PackageParserException if the APK's signature failed to verify.
303 * or greater is not found, except in the case of no JAR signature.
304 */
Gavin Corkeryed521ab2019-01-31 16:59:41 +0000305 public static PackageParser.SigningDetails unsafeGetCertsWithoutVerification(
Patrick Baumann420d58a2017-12-19 10:17:21 -0800306 String apkPath, int minSignatureSchemeVersion)
Dan Cashman636ea5e2017-12-18 10:38:20 -0800307 throws PackageParserException {
308
Patrick Baumann420d58a2017-12-19 10:17:21 -0800309 if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V3) {
Daniel Cashman67096e02017-12-28 12:46:33 -0800310 // V3 and before are older than the requested minimum signing version
311 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
312 "No signature found in package of version " + minSignatureSchemeVersion
313 + " or newer for package " + apkPath);
314 }
315
316 // first try v3
Daniel Cashman77029c52018-01-18 16:19:29 -0800317 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "certsOnlyV3");
Daniel Cashman67096e02017-12-28 12:46:33 -0800318 try {
319 ApkSignatureSchemeV3Verifier.VerifiedSigner vSigner =
Gavin Corkeryed521ab2019-01-31 16:59:41 +0000320 ApkSignatureSchemeV3Verifier.unsafeGetCertsWithoutVerification(apkPath);
Daniel Cashman67096e02017-12-28 12:46:33 -0800321 Certificate[][] signerCerts = new Certificate[][] { vSigner.certs };
322 Signature[] signerSigs = convertToSignatures(signerCerts);
Daniel Cashman77029c52018-01-18 16:19:29 -0800323 Signature[] pastSignerSigs = null;
Daniel Cashman77029c52018-01-18 16:19:29 -0800324 if (vSigner.por != null) {
325 // populate proof-of-rotation information
326 pastSignerSigs = new Signature[vSigner.por.certs.size()];
Daniel Cashman77029c52018-01-18 16:19:29 -0800327 for (int i = 0; i < pastSignerSigs.length; i++) {
328 pastSignerSigs[i] = new Signature(vSigner.por.certs.get(i).getEncoded());
Michael Groovera117b0d2018-07-23 12:55:54 -0700329 pastSignerSigs[i].setFlags(vSigner.por.flagsList.get(i));
Daniel Cashman77029c52018-01-18 16:19:29 -0800330 }
331 }
332 return new PackageParser.SigningDetails(
333 signerSigs, SignatureSchemeVersion.SIGNING_BLOCK_V3,
Michael Groovera117b0d2018-07-23 12:55:54 -0700334 pastSignerSigs);
Daniel Cashman67096e02017-12-28 12:46:33 -0800335 } catch (SignatureNotFoundException e) {
Daniel Cashman77029c52018-01-18 16:19:29 -0800336 // not signed with v3, try older if allowed
Patrick Baumann420d58a2017-12-19 10:17:21 -0800337 if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V3) {
Daniel Cashman67096e02017-12-28 12:46:33 -0800338 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
339 "No APK Signature Scheme v3 signature in package " + apkPath, e);
340 }
341 } catch (Exception e) {
Daniel Cashman77029c52018-01-18 16:19:29 -0800342 // APK Signature Scheme v3 signature found but did not verify
Daniel Cashman67096e02017-12-28 12:46:33 -0800343 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
344 "Failed to collect certificates from " + apkPath
Daniel Cashman77029c52018-01-18 16:19:29 -0800345 + " using APK Signature Scheme v3", e);
Daniel Cashman67096e02017-12-28 12:46:33 -0800346 } finally {
347 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
348 }
349
350 // redundant, protective version check
Patrick Baumann420d58a2017-12-19 10:17:21 -0800351 if (minSignatureSchemeVersion > SignatureSchemeVersion.SIGNING_BLOCK_V2) {
Daniel Cashman67096e02017-12-28 12:46:33 -0800352 // V2 and before are older than the requested minimum signing version
353 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
354 "No signature found in package of version " + minSignatureSchemeVersion
355 + " or newer for package " + apkPath);
356 }
357
Dan Cashman636ea5e2017-12-18 10:38:20 -0800358 // first try v2
359 Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "certsOnlyV2");
360 try {
361 Certificate[][] signerCerts =
Gavin Corkeryed521ab2019-01-31 16:59:41 +0000362 ApkSignatureSchemeV2Verifier.unsafeGetCertsWithoutVerification(apkPath);
Dan Cashman636ea5e2017-12-18 10:38:20 -0800363 Signature[] signerSigs = convertToSignatures(signerCerts);
Patrick Baumann420d58a2017-12-19 10:17:21 -0800364 return new PackageParser.SigningDetails(signerSigs,
365 SignatureSchemeVersion.SIGNING_BLOCK_V2);
Dan Cashman636ea5e2017-12-18 10:38:20 -0800366 } catch (SignatureNotFoundException e) {
367 // not signed with v2, try older if allowed
Patrick Baumann420d58a2017-12-19 10:17:21 -0800368 if (minSignatureSchemeVersion >= SignatureSchemeVersion.SIGNING_BLOCK_V2) {
Dan Cashman636ea5e2017-12-18 10:38:20 -0800369 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
370 "No APK Signature Scheme v2 signature in package " + apkPath, e);
371 }
372 } catch (Exception e) {
373 // APK Signature Scheme v2 signature found but did not verify
374 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
375 "Failed to collect certificates from " + apkPath
376 + " using APK Signature Scheme v2", e);
377 } finally {
378 Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
379 }
380
Daniel Cashman67096e02017-12-28 12:46:33 -0800381 // redundant, protective version check
Patrick Baumann420d58a2017-12-19 10:17:21 -0800382 if (minSignatureSchemeVersion > SignatureSchemeVersion.JAR) {
Daniel Cashman67096e02017-12-28 12:46:33 -0800383 // V1 and is older than the requested minimum signing version
384 throw new PackageParserException(INSTALL_PARSE_FAILED_NO_CERTIFICATES,
385 "No signature found in package of version " + minSignatureSchemeVersion
386 + " or newer for package " + apkPath);
387 }
388
Dan Cashman636ea5e2017-12-18 10:38:20 -0800389 // v2 didn't work, try jarsigner
390 return verifyV1Signature(apkPath, false);
391 }
Victor Hsieh07bc80c2018-01-11 16:15:47 -0800392
393 /**
394 * @return the verity root hash in the Signing Block.
395 */
396 public static byte[] getVerityRootHash(String apkPath)
397 throws IOException, SignatureNotFoundException, SecurityException {
398 // first try v3
399 try {
400 return ApkSignatureSchemeV3Verifier.getVerityRootHash(apkPath);
401 } catch (SignatureNotFoundException e) {
402 // try older version
403 }
404 return ApkSignatureSchemeV2Verifier.getVerityRootHash(apkPath);
405 }
406
407 /**
408 * Generates the Merkle tree and verity metadata to the buffer allocated by the {@code
409 * ByteBufferFactory}.
410 *
411 * @return the verity root hash of the generated Merkle tree.
412 */
413 public static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory)
414 throws IOException, SignatureNotFoundException, SecurityException, DigestException,
415 NoSuchAlgorithmException {
416 // first try v3
417 try {
418 return ApkSignatureSchemeV3Verifier.generateApkVerity(apkPath, bufferFactory);
419 } catch (SignatureNotFoundException e) {
420 // try older version
421 }
422 return ApkSignatureSchemeV2Verifier.generateApkVerity(apkPath, bufferFactory);
423 }
424
425 /**
Victor Hsieh5f761242018-01-20 10:30:12 -0800426 * Generates the FSVerity root hash from FSVerity header, extensions and Merkle tree root hash
427 * in Signing Block.
428 *
429 * @return FSverity root hash
430 */
Victor Hsieh25195132018-09-06 16:32:06 -0700431 public static byte[] generateApkVerityRootHash(String apkPath)
Victor Hsieh5f761242018-01-20 10:30:12 -0800432 throws NoSuchAlgorithmException, DigestException, IOException {
433 // first try v3
434 try {
Victor Hsieh25195132018-09-06 16:32:06 -0700435 return ApkSignatureSchemeV3Verifier.generateApkVerityRootHash(apkPath);
Victor Hsieh5f761242018-01-20 10:30:12 -0800436 } catch (SignatureNotFoundException e) {
437 // try older version
438 }
439 try {
Victor Hsieh25195132018-09-06 16:32:06 -0700440 return ApkSignatureSchemeV2Verifier.generateApkVerityRootHash(apkPath);
Victor Hsieh5f761242018-01-20 10:30:12 -0800441 } catch (SignatureNotFoundException e) {
442 return null;
443 }
444 }
445
446 /**
Victor Hsieh07bc80c2018-01-11 16:15:47 -0800447 * Result of a successful APK verification operation.
448 */
449 public static class Result {
450 public final Certificate[][] certs;
451 public final Signature[] sigs;
452 public final int signatureSchemeVersion;
453
454 public Result(Certificate[][] certs, Signature[] sigs, int signingVersion) {
455 this.certs = certs;
456 this.sigs = sigs;
457 this.signatureSchemeVersion = signingVersion;
458 }
459 }
Dan Cashmane92f8422017-12-08 14:02:51 -0800460}