diff --git a/tools/apksigner/core/src/com/android/apksigner/core/ApkSignerEngine.java b/tools/apksigner/core/src/com/android/apksigner/core/ApkSignerEngine.java index 36f2a08e99..6a148ca2a3 100644 --- a/tools/apksigner/core/src/com/android/apksigner/core/ApkSignerEngine.java +++ b/tools/apksigner/core/src/com/android/apksigner/core/ApkSignerEngine.java @@ -19,6 +19,7 @@ package com.android.apksigner.core; import java.io.Closeable; import java.io.IOException; import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; import java.security.SignatureException; import java.util.List; @@ -182,13 +183,17 @@ public interface ApkSignerEngine extends Closeable { * request must be fulfilled before * {@link #outputZipSections(DataSource, DataSource, DataSource)} is invoked. * + * @throws NoSuchAlgorithmException if a signature could not be generated because a required + * cryptographic algorithm implementation is missing * @throws InvalidKeyException if a signature could not be generated because a signing key is * not suitable for generating the signature - * @throws SignatureException if an error occurred while generating the JAR signature + * @throws SignatureException if an error occurred while generating a signature * @throws IllegalStateException if there are unfulfilled requests, such as to inspect some JAR * entries, or if the engine is closed */ - OutputJarSignatureRequest outputJarEntries() throws InvalidKeyException, SignatureException; + OutputJarSignatureRequest outputJarEntries() + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, + IllegalStateException; /** * Indicates to this engine that the ZIP sections comprising the output APK have been output. @@ -207,16 +212,20 @@ public interface ApkSignerEngine extends Closeable { * {@link #outputDone()} is invoked. * * @throws IOException if an I/O error occurs while reading the provided ZIP sections + * @throws NoSuchAlgorithmException if a signature could not be generated because a required + * cryptographic algorithm implementation is missing * @throws InvalidKeyException if a signature could not be generated because a signing key is * not suitable for generating the signature - * @throws SignatureException if an error occurred while generating the APK's signature + * @throws SignatureException if an error occurred while generating a signature * @throws IllegalStateException if there are unfulfilled requests, such as to inspect some JAR * entries or to output JAR signature, or if the engine is closed */ OutputApkSigningBlockRequest outputZipSections( DataSource zipEntries, DataSource zipCentralDirectory, - DataSource zipEocd) throws IOException, InvalidKeyException, SignatureException; + DataSource zipEocd) + throws IOException, NoSuchAlgorithmException, InvalidKeyException, + SignatureException, IllegalStateException; /** * Indicates to this engine that the signed APK was output. diff --git a/tools/apksigner/core/src/com/android/apksigner/core/ApkVerifier.java b/tools/apksigner/core/src/com/android/apksigner/core/ApkVerifier.java index c3999b569a..d509a48dc7 100644 --- a/tools/apksigner/core/src/com/android/apksigner/core/ApkVerifier.java +++ b/tools/apksigner/core/src/com/android/apksigner/core/ApkVerifier.java @@ -26,6 +26,7 @@ import com.android.apksigner.core.util.DataSource; import com.android.apksigner.core.zip.ZipFormatException; import java.io.IOException; +import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateEncodingException; import java.security.cert.X509Certificate; import java.util.ArrayList; @@ -61,9 +62,11 @@ public class ApkVerifier { * * @throws IOException if an I/O error is encountered while reading the APK * @throws ZipFormatException if the APK is malformed at ZIP format level + * @throws NoSuchAlgorithmException if the APK's signatures cannot be verified because a + * required cryptographic algorithm implementation is missing */ public Result verify(DataSource apk, int minSdkVersion, int maxSdkVersion) - throws IOException, ZipFormatException { + throws IOException, ZipFormatException, NoSuchAlgorithmException { if (minSdkVersion < 0) { throw new IllegalArgumentException( "minSdkVersion must not be negative: " + minSdkVersion); diff --git a/tools/apksigner/core/src/com/android/apksigner/core/DefaultApkSignerEngine.java b/tools/apksigner/core/src/com/android/apksigner/core/DefaultApkSignerEngine.java index 52042ac9d8..75b0b20420 100644 --- a/tools/apksigner/core/src/com/android/apksigner/core/DefaultApkSignerEngine.java +++ b/tools/apksigner/core/src/com/android/apksigner/core/DefaultApkSignerEngine.java @@ -293,7 +293,7 @@ public class DefaultApkSignerEngine implements ApkSignerEngine { @Override public OutputJarSignatureRequest outputJarEntries() - throws InvalidKeyException, SignatureException { + throws InvalidKeyException, SignatureException, NoSuchAlgorithmException { checkNotClosed(); if (!mV1SignaturePending) { @@ -413,7 +413,9 @@ public class DefaultApkSignerEngine implements ApkSignerEngine { public OutputApkSigningBlockRequest outputZipSections( DataSource zipEntries, DataSource zipCentralDirectory, - DataSource zipEocd) throws IOException, InvalidKeyException, SignatureException { + DataSource zipEocd) + throws IOException, InvalidKeyException, SignatureException, + NoSuchAlgorithmException { checkNotClosed(); checkV1SigningDoneIfEnabled(); if (!mV2SigningEnabled) { diff --git a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeSigner.java b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeSigner.java index 1a4a90bb83..f124d16976 100644 --- a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeSigner.java +++ b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeSigner.java @@ -155,13 +155,10 @@ public abstract class V1SchemeSigner { /** * Returns a new {@link MessageDigest} instance corresponding to the provided digest algorithm. */ - public static MessageDigest getMessageDigestInstance(DigestAlgorithm digestAlgorithm) { + private static MessageDigest getMessageDigestInstance(DigestAlgorithm digestAlgorithm) + throws NoSuchAlgorithmException { String jcaAlgorithm = digestAlgorithm.getJcaMessageDigestAlgorithm(); - try { - return MessageDigest.getInstance(jcaAlgorithm); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Failed to obtain " + jcaAlgorithm + " MessageDigest", e); - } + return MessageDigest.getInstance(jcaAlgorithm); } /** @@ -215,6 +212,8 @@ public abstract class V1SchemeSigner { * @param signerConfigs signer configurations, one for each signer. At least one signer config * must be provided. * + * @throws NoSuchAlgorithmException if a required cryptographic algorithm implementation is + * missing * @throws InvalidKeyException if a signing key is not suitable for this signature scheme or * cannot be used in general * @throws SignatureException if an error occurs when computing digests of generating @@ -226,7 +225,8 @@ public abstract class V1SchemeSigner { Map jarEntryDigests, List apkSigningSchemeIds, byte[] sourceManifestBytes) - throws InvalidKeyException, CertificateException, SignatureException { + throws NoSuchAlgorithmException, InvalidKeyException, CertificateException, + SignatureException { if (signerConfigs.isEmpty()) { throw new IllegalArgumentException("At least one signer config must be provided"); } @@ -253,7 +253,8 @@ public abstract class V1SchemeSigner { DigestAlgorithm digestAlgorithm, List apkSigningSchemeIds, OutputManifestFile manifest) - throws InvalidKeyException, CertificateException, SignatureException { + throws NoSuchAlgorithmException, InvalidKeyException, CertificateException, + SignatureException { if (signerConfigs.isEmpty()) { throw new IllegalArgumentException("At least one signer config must be provided"); } @@ -378,7 +379,7 @@ public abstract class V1SchemeSigner { private static byte[] generateSignatureFile( List apkSignatureSchemeIds, DigestAlgorithm manifestDigestAlgorithm, - OutputManifestFile manifest) { + OutputManifestFile manifest) throws NoSuchAlgorithmException { Manifest sf = new Manifest(); Attributes mainAttrs = sf.getMainAttributes(); mainAttrs.put(Attributes.Name.SIGNATURE_VERSION, ATTRIBUTE_VALUE_SIGNATURE_VERSION); @@ -447,7 +448,8 @@ public abstract class V1SchemeSigner { @SuppressWarnings("restriction") private static byte[] generateSignatureBlock( SignerConfig signerConfig, byte[] signatureFileBytes) - throws InvalidKeyException, CertificateException, SignatureException { + throws NoSuchAlgorithmException, InvalidKeyException, CertificateException, + SignatureException { List signerCerts = signerConfig.certificates; X509Certificate signerCert = signerCerts.get(0); PublicKey signerPublicKey = signerCert.getPublicKey(); @@ -455,16 +457,10 @@ public abstract class V1SchemeSigner { Pair signatureAlgs = getSignerInfoSignatureAlgorithm(signerPublicKey, digestAlgorithm); String jcaSignatureAlgorithm = signatureAlgs.getFirst(); - byte[] signatureBytes; - try { - Signature signature = Signature.getInstance(jcaSignatureAlgorithm); - signature.initSign(signerConfig.privateKey); - signature.update(signatureFileBytes); - signatureBytes = signature.sign(); - } catch (NoSuchAlgorithmException e) { - throw new SignatureException( - jcaSignatureAlgorithm + " Signature implementation not found", e); - } + Signature signature = Signature.getInstance(jcaSignatureAlgorithm); + signature.initSign(signerConfig.privateKey); + signature.update(signatureFileBytes); + byte[] signatureBytes = signature.sign(); X500Name issuerName; try { diff --git a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeVerifier.java b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeVerifier.java index 60a47b2a21..1bba313232 100644 --- a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeVerifier.java +++ b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v1/V1SchemeVerifier.java @@ -72,6 +72,8 @@ public abstract class V1SchemeVerifier { * * @throws ZipFormatException if the APK is malformed * @throws IOException if an I/O error occurs when reading the APK + * @throws NoSuchAlgorithmException if the APK's JAR signatures cannot be verified because a + * required cryptographic algorithm implementation is missing */ public static Result verify( DataSource apk, @@ -79,7 +81,7 @@ public abstract class V1SchemeVerifier { Map supportedApkSigSchemeNames, Set foundApkSigSchemeIds, int minSdkVersion, - int maxSdkVersion) throws IOException, ZipFormatException { + int maxSdkVersion) throws IOException, ZipFormatException, NoSuchAlgorithmException { if (minSdkVersion > maxSdkVersion) { throw new IllegalArgumentException( "minSdkVersion (" + minSdkVersion + ") > maxSdkVersion (" + maxSdkVersion @@ -152,7 +154,7 @@ public abstract class V1SchemeVerifier { Set foundApkSigSchemeIds, int minSdkVersion, int maxSdkVersion, - Result result) throws ZipFormatException, IOException { + Result result) throws ZipFormatException, IOException, NoSuchAlgorithmException { // Find JAR manifest and signature block files. CentralDirectoryRecord manifestEntry = null; @@ -312,6 +314,8 @@ public abstract class V1SchemeVerifier { cdRecords, entryNameToManifestSection, signers, + minSdkVersion, + maxSdkVersion, result); if (result.containsErrors()) { return; @@ -405,7 +409,7 @@ public abstract class V1SchemeVerifier { @SuppressWarnings("restriction") public void verifySigBlockAgainstSigFile( DataSource apk, long cdStartOffset, int minSdkVersion, int maxSdkVersion) - throws IOException, ZipFormatException { + throws IOException, ZipFormatException, NoSuchAlgorithmException { byte[] sigBlockBytes = LocalFileHeader.getUncompressedData( apk, 0, @@ -461,7 +465,7 @@ public abstract class V1SchemeVerifier { } try { verifiedSignerInfo = sigBlock.verify(unverifiedSignerInfo, mSigFileBytes); - } catch (NoSuchAlgorithmException | SignatureException e) { + } catch (SignatureException e) { mResult.addError( Issue.JAR_SIG_VERIFY_EXCEPTION, mSignatureBlockEntry.getName(), @@ -856,7 +860,7 @@ public abstract class V1SchemeVerifier { Map supportedApkSigSchemeNames, Set foundApkSigSchemeIds, int minSdkVersion, - int maxSdkVersion) { + int maxSdkVersion) throws NoSuchAlgorithmException { // Inspect the main section of the .SF file. ManifestParser sf = new ManifestParser(mSigFileBytes); ManifestParser.Section sfMainSection = sf.readSection(); @@ -965,7 +969,7 @@ public abstract class V1SchemeVerifier { boolean createdBySigntool, byte[] manifestBytes, int minSdkVersion, - int maxSdkVersion) { + int maxSdkVersion) throws NoSuchAlgorithmException { Collection expectedDigests = getDigestsToVerify( sfMainSection, @@ -1008,7 +1012,7 @@ public abstract class V1SchemeVerifier { ManifestParser.Section manifestMainSection, byte[] manifestBytes, int minSdkVersion, - int maxSdkVersion) { + int maxSdkVersion) throws NoSuchAlgorithmException { Collection expectedDigests = getDigestsToVerify( sfMainSection, @@ -1049,7 +1053,7 @@ public abstract class V1SchemeVerifier { ManifestParser.Section manifestIndividualSection, byte[] manifestBytes, int minSdkVersion, - int maxSdkVersion) { + int maxSdkVersion) throws NoSuchAlgorithmException { String entryName = sfIndividualSection.getName(); Collection expectedDigests = getDigestsToVerify( @@ -1344,7 +1348,9 @@ public abstract class V1SchemeVerifier { Collection cdRecords, Map entryNameToManifestSection, List signers, - Result result) throws ZipFormatException, IOException { + int minSdkVersion, + int maxSdkVersion, + Result result) throws ZipFormatException, IOException, NoSuchAlgorithmException { // Iterate over APK contents as sequentially as possible to improve performance. List cdRecordsSortedByLocalFileHeaderOffset = new ArrayList<>(cdRecords); @@ -1391,22 +1397,8 @@ public abstract class V1SchemeVerifier { continue; } - List expectedDigests = new ArrayList<>(); - for (ManifestParser.Attribute attr : manifestSection.getAttributes()) { - String name = attr.getName(); - String nameUpperCase = name.toUpperCase(Locale.US); - if (!nameUpperCase.endsWith("-DIGEST")) { - continue; - } - String jcaDigestAlgorithm = - nameUpperCase.substring(0, nameUpperCase.length() - "-DIGEST".length()); - if ("SHA1".equals(jcaDigestAlgorithm)) { - jcaDigestAlgorithm = "SHA-1"; - } - byte[] digest = Base64.getDecoder().decode(attr.getValue()); - expectedDigests.add(new NamedDigest(jcaDigestAlgorithm, digest)); - } - + Collection expectedDigests = + getDigestsToVerify(manifestSection, "-Digest", minSdkVersion, maxSdkVersion); if (expectedDigests.isEmpty()) { result.addError(Issue.JAR_SIG_NO_ZIP_ENTRY_DIGEST_IN_MANIFEST, entryName); continue; @@ -1465,21 +1457,19 @@ public abstract class V1SchemeVerifier { return result; } - private static MessageDigest getMessageDigest(String algorithm) { - try { - return MessageDigest.getInstance(algorithm); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("Failed to obtain " + algorithm + " MessageDigest", e); - } + private static MessageDigest getMessageDigest(String algorithm) + throws NoSuchAlgorithmException { + return MessageDigest.getInstance(algorithm); } - private static byte[] digest(String algorithm, byte[] data, int offset, int length) { + private static byte[] digest(String algorithm, byte[] data, int offset, int length) + throws NoSuchAlgorithmException { MessageDigest md = getMessageDigest(algorithm); md.update(data, offset, length); return md.digest(); } - private static byte[] digest(String algorithm, byte[] data) { + private static byte[] digest(String algorithm, byte[] data) throws NoSuchAlgorithmException { return getMessageDigest(algorithm).digest(data); } diff --git a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v2/V2SchemeSigner.java b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v2/V2SchemeSigner.java index aba390b2a2..06d31dd1f6 100644 --- a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v2/V2SchemeSigner.java +++ b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v2/V2SchemeSigner.java @@ -163,6 +163,8 @@ public abstract class V2SchemeSigner { * must be provided. * * @throws IOException if an I/O error occurs + * @throws NoSuchAlgorithmException if a required cryptographic algorithm implementation is + * missing * @throws InvalidKeyException if a signing key is not suitable for this signature scheme or * cannot be used in general * @throws SignatureException if an error occurs when computing digests of generating @@ -173,7 +175,8 @@ public abstract class V2SchemeSigner { DataSource centralDir, DataSource eocd, List signerConfigs) - throws IOException, InvalidKeyException, SignatureException { + throws IOException, NoSuchAlgorithmException, InvalidKeyException, + SignatureException { if (signerConfigs.isEmpty()) { throw new IllegalArgumentException( "No signer configs provided. At least one is required"); @@ -219,7 +222,7 @@ public abstract class V2SchemeSigner { static Map computeContentDigests( Set digestAlgorithms, - DataSource[] contents) throws IOException, DigestException { + DataSource[] contents) throws IOException, NoSuchAlgorithmException, DigestException { // For each digest algorithm the result is computed as follows: // 1. Each segment of contents is split into consecutive chunks of 1 MB in size. // The final chunk will be shorter iff the length of segment is not a multiple of 1 MB. @@ -256,11 +259,7 @@ public abstract class V2SchemeSigner { chunkCount, concatenationOfChunkCountAndChunkDigests, 1); digestsOfChunks[i] = concatenationOfChunkCountAndChunkDigests; String jcaAlgorithm = digestAlgorithm.getJcaMessageDigestAlgorithm(); - try { - mds[i] = MessageDigest.getInstance(jcaAlgorithm); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException(jcaAlgorithm + " MessageDigest not supported", e); - } + mds[i] = MessageDigest.getInstance(jcaAlgorithm); } MessageDigestSink mdSink = new MessageDigestSink(mds); @@ -338,7 +337,7 @@ public abstract class V2SchemeSigner { private static byte[] generateApkSigningBlock( List signerConfigs, Map contentDigests) - throws InvalidKeyException, SignatureException { + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { byte[] apkSignatureSchemeV2Block = generateApkSignatureSchemeV2Block(signerConfigs, contentDigests); return generateApkSigningBlock(apkSignatureSchemeV2Block); @@ -379,7 +378,7 @@ public abstract class V2SchemeSigner { private static byte[] generateApkSignatureSchemeV2Block( List signerConfigs, Map contentDigests) - throws InvalidKeyException, SignatureException { + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { // FORMAT: // * length-prefixed sequence of length-prefixed signer blocks. @@ -407,7 +406,7 @@ public abstract class V2SchemeSigner { private static byte[] generateSignerBlock( SignerConfig signerConfig, Map contentDigests) - throws InvalidKeyException, SignatureException { + throws NoSuchAlgorithmException, InvalidKeyException, SignatureException { if (signerConfig.certificates.isEmpty()) { throw new SignatureException("No certificates configured for signer"); } @@ -470,10 +469,9 @@ public abstract class V2SchemeSigner { signature.update(signer.signedData); signatureBytes = signature.sign(); } catch (InvalidKeyException e) { - throw new InvalidKeyException("Failed sign using " + jcaSignatureAlgorithm, e); - } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException - | SignatureException e) { - throw new SignatureException("Failed sign using " + jcaSignatureAlgorithm, e); + throw new InvalidKeyException("Failed to sign using " + jcaSignatureAlgorithm, e); + } catch (InvalidAlgorithmParameterException | SignatureException e) { + throw new SignatureException("Failed to sign using " + jcaSignatureAlgorithm, e); } try { @@ -487,12 +485,13 @@ public abstract class V2SchemeSigner { throw new SignatureException("Signature did not verify"); } } catch (InvalidKeyException e) { - throw new InvalidKeyException("Failed to verify generated " + jcaSignatureAlgorithm - + " signature using public key from certificate", e); - } catch (NoSuchAlgorithmException | InvalidAlgorithmParameterException - | SignatureException e) { - throw new SignatureException("Failed to verify generated " + jcaSignatureAlgorithm - + " signature using public key from certificate", e); + throw new InvalidKeyException( + "Failed to verify generated " + jcaSignatureAlgorithm + " signature using" + + " public key from certificate", e); + } catch (InvalidAlgorithmParameterException | SignatureException e) { + throw new SignatureException( + "Failed to verify generated " + jcaSignatureAlgorithm + " signature using" + + " public key from certificate", e); } signer.signatures.add(Pair.of(signatureAlgorithm.getId(), signatureBytes)); @@ -526,7 +525,8 @@ public abstract class V2SchemeSigner { } } - private static byte[] encodePublicKey(PublicKey publicKey) throws InvalidKeyException { + private static byte[] encodePublicKey(PublicKey publicKey) + throws InvalidKeyException, NoSuchAlgorithmException { byte[] encodedPublicKey = null; if ("X.509".equals(publicKey.getFormat())) { encodedPublicKey = publicKey.getEncoded(); @@ -537,11 +537,6 @@ public abstract class V2SchemeSigner { KeyFactory.getInstance(publicKey.getAlgorithm()) .getKeySpec(publicKey, X509EncodedKeySpec.class) .getEncoded(); - } catch (NoSuchAlgorithmException e) { - throw new InvalidKeyException( - "Failed to obtain X.509 encoded form of public key " + publicKey - + " of class " + publicKey.getClass().getName(), - e); } catch (InvalidKeySpecException e) { throw new InvalidKeyException( "Failed to obtain X.509 encoded form of public key " + publicKey diff --git a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v2/V2SchemeVerifier.java b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v2/V2SchemeVerifier.java index efefb0051d..0c303ee3dc 100644 --- a/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v2/V2SchemeVerifier.java +++ b/tools/apksigner/core/src/com/android/apksigner/core/internal/apk/v2/V2SchemeVerifier.java @@ -31,9 +31,13 @@ import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.security.DigestException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; import java.security.PublicKey; import java.security.Signature; +import java.security.SignatureException; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; @@ -74,11 +78,13 @@ public abstract class V2SchemeVerifier { * verification. APK is considered verified only if {@link Result#verified} is {@code true}. If * verification fails, the result will contain errors -- see {@link Result#getErrors()}. * + * @throws NoSuchAlgorithmException if the APK's signatures cannot be verified because a + * required cryptographic algorithm implementation is missing * @throws SignatureNotFoundException if no APK Signature Scheme v2 signatures are found * @throws IOException if an I/O error occurs when reading the APK */ public static Result verify(DataSource apk, ApkUtils.ZipSections zipSections) - throws IOException, SignatureNotFoundException { + throws IOException, NoSuchAlgorithmException, SignatureNotFoundException { Result result = new Result(); SignatureInfo signatureInfo = findSignature(apk, zipSections, result); @@ -107,7 +113,7 @@ public abstract class V2SchemeVerifier { ByteBuffer apkSignatureSchemeV2Block, DataSource centralDir, ByteBuffer eocd, - Result result) throws IOException { + Result result) throws IOException, NoSuchAlgorithmException { Set contentDigestsToVerify = new HashSet<>(1); parseSigners(apkSignatureSchemeV2Block, contentDigestsToVerify, result); if (result.containsErrors()) { @@ -131,7 +137,7 @@ public abstract class V2SchemeVerifier { private static void parseSigners( ByteBuffer apkSignatureSchemeV2Block, Set contentDigestsToVerify, - Result result) { + Result result) throws NoSuchAlgorithmException { ByteBuffer signers; try { signers = getLengthPrefixedSlice(apkSignatureSchemeV2Block); @@ -178,7 +184,8 @@ public abstract class V2SchemeVerifier { ByteBuffer signerBlock, CertificateFactory certFactory, Result.SignerInfo result, - Set contentDigestsToVerify) throws IOException { + Set contentDigestsToVerify) + throws IOException, NoSuchAlgorithmException { ByteBuffer signedData = getLengthPrefixedSlice(signerBlock); byte[] signedDataBytes = new byte[signedData.remaining()]; signedData.get(signedDataBytes); @@ -252,7 +259,8 @@ public abstract class V2SchemeVerifier { } result.verifiedSignatures.put(signatureAlgorithm, sigBytes); contentDigestsToVerify.add(signatureAlgorithm.getContentDigestAlgorithm()); - } catch (Exception e) { + } catch (InvalidKeyException | InvalidAlgorithmParameterException + | SignatureException e) { result.addError(Issue.V2_SIG_VERIFY_EXCEPTION, signatureAlgorithm, e); return; } @@ -440,7 +448,7 @@ public abstract class V2SchemeVerifier { DataSource centralDir, ByteBuffer eocd, Set contentDigestAlgorithms, - Result result) throws IOException { + Result result) throws IOException, NoSuchAlgorithmException { if (contentDigestAlgorithms.isEmpty()) { // This should never occur because this method is invoked once at least one signature // is verified, meaning at least one content digest is known.