Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 8427083a authored by Alex Klyubin's avatar Alex Klyubin Committed by Gerrit Code Review
Browse files

Merge "Let caller handle NoSuchAlgorithmException."

parents 2ea2e205 05f87de7
Loading
Loading
Loading
Loading
+13 −4
Original line number Diff line number Diff line
@@ -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.
+4 −1
Original line number Diff line number Diff line
@@ -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);
+4 −2
Original line number Diff line number Diff line
@@ -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) {
+16 −20
Original line number Diff line number Diff line
@@ -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);
        }
    }

    /**
@@ -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<String, byte[]> jarEntryDigests,
            List<Integer> 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<Integer> 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<Integer> 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<X509Certificate> signerCerts = signerConfig.certificates;
        X509Certificate signerCert = signerCerts.get(0);
        PublicKey signerPublicKey = signerCert.getPublicKey();
@@ -455,16 +457,10 @@ public abstract class V1SchemeSigner {
        Pair<String, AlgorithmId> 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);
        }
        byte[] signatureBytes = signature.sign();

        X500Name issuerName;
        try {
+23 −33
Original line number Diff line number Diff line
@@ -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<Integer, String> supportedApkSigSchemeNames,
            Set<Integer> 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<Integer> 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<Integer, String> supportedApkSigSchemeNames,
                Set<Integer> 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<NamedDigest> 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<NamedDigest> 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<NamedDigest> expectedDigests =
                    getDigestsToVerify(
@@ -1344,7 +1348,9 @@ public abstract class V1SchemeVerifier {
            Collection<CentralDirectoryRecord> cdRecords,
            Map<String, ManifestParser.Section> entryNameToManifestSection,
            List<Signer> 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<CentralDirectoryRecord> cdRecordsSortedByLocalFileHeaderOffset =
                new ArrayList<>(cdRecords);
@@ -1391,22 +1397,8 @@ public abstract class V1SchemeVerifier {
                continue;
            }

            List<NamedDigest> 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<NamedDigest> 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 {
    private static MessageDigest getMessageDigest(String algorithm)
            throws NoSuchAlgorithmException {
        return MessageDigest.getInstance(algorithm);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("Failed to obtain " + algorithm + " MessageDigest", e);
        }
    }

    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);
    }

Loading