Search in sources :

Example 1 with ApkFormatException

use of com.android.apksig.apk.ApkFormatException in project AppManager by MuntashirAkon.

the class AppDetailsViewModel method loadSignatures.

@SuppressWarnings("deprecation")
@WorkerThread
private void loadSignatures() {
    List<AppDetailsItem<X509Certificate>> appDetailsItems = new ArrayList<>();
    if (mApkFile == null) {
        mSignatures.postValue(appDetailsItems);
        return;
    }
    try {
        File idsigFile = mApkFile.getIdsigFile();
        ApkVerifier.Builder builder = new ApkVerifier.Builder(mApkFile.getBaseEntry().getRealCachedFile());
        if (idsigFile != null) {
            builder.setV4SignatureFile(idsigFile);
        }
        ApkVerifier apkVerifier = builder.build();
        mApkVerifierResult = apkVerifier.verify();
        // Get signer certificates
        List<X509Certificate> certificates = mApkVerifierResult.getSignerCertificates();
        if (certificates != null && certificates.size() > 0) {
            for (X509Certificate certificate : certificates) {
                AppDetailsItem<X509Certificate> item = new AppDetailsItem<>(certificate);
                item.name = "Signer Certificate";
                appDetailsItems.add(item);
            }
            if (mIsExternalApk && mPackageInfo.signatures == null) {
                List<Signature> signatures = new ArrayList<>(certificates.size());
                for (X509Certificate certificate : certificates) {
                    try {
                        signatures.add(new Signature(certificate.getEncoded()));
                    } catch (CertificateEncodingException ignore) {
                    }
                }
                mPackageInfo.signatures = signatures.toArray(new Signature[0]);
            }
        } else {
            // noinspection ConstantConditions Null is deliberately set here to get at least one row
            appDetailsItems.add(new AppDetailsItem<>(null));
        }
        // Get source stamp certificate
        if (mApkVerifierResult.isSourceStampVerified()) {
            ApkVerifier.Result.SourceStampInfo sourceStampInfo = mApkVerifierResult.getSourceStampInfo();
            X509Certificate certificate = sourceStampInfo.getCertificate();
            if (certificate != null) {
                AppDetailsItem<X509Certificate> item = new AppDetailsItem<>(certificate);
                item.name = "SourceStamp Certificate";
                appDetailsItems.add(item);
            }
        }
        SigningCertificateLineage lineage = mApkVerifierResult.getSigningCertificateLineage();
        if (lineage != null) {
            certificates = lineage.getCertificatesInLineage();
            if (certificates != null && certificates.size() > 0) {
                for (X509Certificate certificate : certificates) {
                    AppDetailsItem<X509Certificate> item = new AppDetailsItem<>(certificate);
                    item.name = "Certificate for Lineage";
                    appDetailsItems.add(item);
                }
            }
        }
    } catch (IOException | ApkFormatException | NoSuchAlgorithmException e) {
        e.printStackTrace();
    }
    mSignatures.postValue(appDetailsItems);
}
Also used : ArrayList(java.util.ArrayList) CertificateEncodingException(java.security.cert.CertificateEncodingException) IOException(java.io.IOException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) AppDetailsItem(io.github.muntashirakon.AppManager.details.struct.AppDetailsItem) X509Certificate(java.security.cert.X509Certificate) SigningCertificateLineage(com.android.apksig.SigningCertificateLineage) ApkVerifier(com.android.apksig.ApkVerifier) ApkFormatException(com.android.apksig.apk.ApkFormatException) Signature(android.content.pm.Signature) ApkFile(io.github.muntashirakon.AppManager.apk.ApkFile) File(java.io.File) WorkerThread(androidx.annotation.WorkerThread)

Example 2 with ApkFormatException

use of com.android.apksig.apk.ApkFormatException in project bundletool by google.

the class ApkSignatureVerifier method verify.

/**
 * Verifies signature of each APK and returns the public certificate of the app signing key.
 */
static Result verify(ImmutableList<Path> deviceSpecificApks) {
    checkArgument(!deviceSpecificApks.isEmpty(), "Expected non-empty list of device-specific APKs.");
    Optional<X509Certificate> apkSigningKeyCertificate = Optional.empty();
    try {
        for (Path apkPath : deviceSpecificApks) {
            ApkVerifier.Result apkSignatureVerificationResult = new ApkVerifier.Builder(apkPath.toFile()).build().verify();
            if (!apkSignatureVerificationResult.isVerified()) {
                return Result.failure("APK signature invalid for " + apkPath.getFileName());
            }
            X509Certificate currentCertificate = apkSignatureVerificationResult.getSignerCertificates().get(0);
            if (apkSigningKeyCertificate.isPresent()) {
                if (!apkSigningKeyCertificate.get().equals(currentCertificate)) {
                    return Result.failure("APK signature verification failed: the keys used to sign the given set of device" + " specific APKs do not match.");
                }
            } else {
                apkSigningKeyCertificate = Optional.of(currentCertificate);
            }
        }
    } catch (IOException | ApkFormatException | NoSuchAlgorithmException e) {
        throw CommandExecutionException.builder().withInternalMessage("Exception during APK signature verification.").withCause(e).build();
    }
    return Result.success(CodeTransparencyCryptoUtils.getCertificateFingerprint(apkSigningKeyCertificate.get()));
}
Also used : Path(java.nio.file.Path) ApkVerifier(com.android.apksig.ApkVerifier) ApkFormatException(com.android.apksig.apk.ApkFormatException) IOException(java.io.IOException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) X509Certificate(java.security.cert.X509Certificate)

Example 3 with ApkFormatException

use of com.android.apksig.apk.ApkFormatException in project apksig by venshine.

the class V1SchemeSigner method generateManifestFile.

/**
 * Generated and returns the {@code META-INF/MANIFEST.MF} file based on the provided (optional)
 * input {@code MANIFEST.MF} and digests of JAR entries covered by the manifest.
 */
public static OutputManifestFile generateManifestFile(DigestAlgorithm jarEntryDigestAlgorithm, Map<String, byte[]> jarEntryDigests, byte[] sourceManifestBytes) throws ApkFormatException {
    Manifest sourceManifest = null;
    if (sourceManifestBytes != null) {
        try {
            sourceManifest = new Manifest(new ByteArrayInputStream(sourceManifestBytes));
        } catch (IOException e) {
            throw new ApkFormatException("Malformed source META-INF/MANIFEST.MF", e);
        }
    }
    ByteArrayOutputStream manifestOut = new ByteArrayOutputStream();
    Attributes mainAttrs = new Attributes();
    // JAR/APK.
    if (sourceManifest != null) {
        mainAttrs.putAll(sourceManifest.getMainAttributes());
    } else {
        mainAttrs.put(Attributes.Name.MANIFEST_VERSION, ATTRIBUTE_VALUE_MANIFEST_VERSION);
    }
    try {
        ManifestWriter.writeMainSection(manifestOut, mainAttrs);
    } catch (IOException e) {
        throw new RuntimeException("Failed to write in-memory MANIFEST.MF", e);
    }
    List<String> sortedEntryNames = new ArrayList<>(jarEntryDigests.keySet());
    Collections.sort(sortedEntryNames);
    SortedMap<String, byte[]> invidualSectionsContents = new TreeMap<>();
    String entryDigestAttributeName = getEntryDigestAttributeName(jarEntryDigestAlgorithm);
    for (String entryName : sortedEntryNames) {
        checkEntryNameValid(entryName);
        byte[] entryDigest = jarEntryDigests.get(entryName);
        Attributes entryAttrs = new Attributes();
        entryAttrs.putValue(entryDigestAttributeName, Base64.getEncoder().encodeToString(entryDigest));
        ByteArrayOutputStream sectionOut = new ByteArrayOutputStream();
        byte[] sectionBytes;
        try {
            ManifestWriter.writeIndividualSection(sectionOut, entryName, entryAttrs);
            sectionBytes = sectionOut.toByteArray();
            manifestOut.write(sectionBytes);
        } catch (IOException e) {
            throw new RuntimeException("Failed to write in-memory MANIFEST.MF", e);
        }
        invidualSectionsContents.put(entryName, sectionBytes);
    }
    OutputManifestFile result = new OutputManifestFile();
    result.contents = manifestOut.toByteArray();
    result.mainSectionAttributes = mainAttrs;
    result.individualSectionsContents = invidualSectionsContents;
    return result;
}
Also used : Attributes(java.util.jar.Attributes) ArrayList(java.util.ArrayList) IOException(java.io.IOException) ByteArrayOutputStream(java.io.ByteArrayOutputStream) Manifest(java.util.jar.Manifest) TreeMap(java.util.TreeMap) ByteArrayInputStream(java.io.ByteArrayInputStream) ApkFormatException(com.android.apksig.apk.ApkFormatException)

Example 4 with ApkFormatException

use of com.android.apksig.apk.ApkFormatException in project apksig by venshine.

the class SourceStampVerifier method verifySourceStamp.

/**
 * Verifies the provided {@code apk}'s source stamp signature, including verification of the
 * SHA-256 digest of the stamp signing certificate matches the {@code expectedCertDigest}, and
 * returns the result of the verification.
 *
 * @see #verifySourceStamp(String)
 */
private SourceStampVerifier.Result verifySourceStamp(DataSource apk, String expectedCertDigest) {
    Result result = new Result();
    try {
        ZipSections zipSections = ApkUtilsLite.findZipSections(apk);
        // Attempt to obtain the source stamp's certificate digest from the APK.
        List<CentralDirectoryRecord> cdRecords = ZipUtils.parseZipCentralDirectory(apk, zipSections);
        CentralDirectoryRecord sourceStampCdRecord = null;
        for (CentralDirectoryRecord cdRecord : cdRecords) {
            if (SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME.equals(cdRecord.getName())) {
                sourceStampCdRecord = cdRecord;
                break;
            }
        }
        // APK's signature block to determine the appropriate status to return.
        if (sourceStampCdRecord == null) {
            boolean stampSigningBlockFound;
            try {
                ApkSigningBlockUtilsLite.findSignature(apk, zipSections, SourceStampConstants.V2_SOURCE_STAMP_BLOCK_ID);
                stampSigningBlockFound = true;
            } catch (SignatureNotFoundException e) {
                stampSigningBlockFound = false;
            }
            result.addVerificationError(stampSigningBlockFound ? ApkVerificationIssue.SOURCE_STAMP_SIGNATURE_BLOCK_WITHOUT_CERT_DIGEST : ApkVerificationIssue.SOURCE_STAMP_CERT_DIGEST_AND_SIG_BLOCK_MISSING);
            return result;
        }
        // Verify that the contents of the source stamp certificate digest match the expected
        // value, if provided.
        byte[] sourceStampCertificateDigest = LocalFileRecord.getUncompressedData(apk, sourceStampCdRecord, zipSections.getZipCentralDirectoryOffset());
        if (expectedCertDigest != null) {
            String actualCertDigest = ApkSigningBlockUtilsLite.toHex(sourceStampCertificateDigest);
            if (!expectedCertDigest.equalsIgnoreCase(actualCertDigest)) {
                result.addVerificationError(ApkVerificationIssue.SOURCE_STAMP_EXPECTED_DIGEST_MISMATCH, actualCertDigest, expectedCertDigest);
                return result;
            }
        }
        Map<Integer, Map<ContentDigestAlgorithm, byte[]>> signatureSchemeApkContentDigests = new HashMap<>();
        if (mMaxSdkVersion >= AndroidSdkVersion.P) {
            SignatureInfo signatureInfo;
            try {
                signatureInfo = ApkSigningBlockUtilsLite.findSignature(apk, zipSections, V3SchemeConstants.APK_SIGNATURE_SCHEME_V3_BLOCK_ID);
            } catch (SignatureNotFoundException e) {
                signatureInfo = null;
            }
            if (signatureInfo != null) {
                Map<ContentDigestAlgorithm, byte[]> apkContentDigests = new EnumMap<>(ContentDigestAlgorithm.class);
                parseSigners(signatureInfo.signatureBlock, VERSION_APK_SIGNATURE_SCHEME_V3, apkContentDigests, result);
                signatureSchemeApkContentDigests.put(VERSION_APK_SIGNATURE_SCHEME_V3, apkContentDigests);
            }
        }
        if (mMaxSdkVersion >= AndroidSdkVersion.N && (mMinSdkVersion < AndroidSdkVersion.P || signatureSchemeApkContentDigests.isEmpty())) {
            SignatureInfo signatureInfo;
            try {
                signatureInfo = ApkSigningBlockUtilsLite.findSignature(apk, zipSections, V2SchemeConstants.APK_SIGNATURE_SCHEME_V2_BLOCK_ID);
            } catch (SignatureNotFoundException e) {
                signatureInfo = null;
            }
            if (signatureInfo != null) {
                Map<ContentDigestAlgorithm, byte[]> apkContentDigests = new EnumMap<>(ContentDigestAlgorithm.class);
                parseSigners(signatureInfo.signatureBlock, VERSION_APK_SIGNATURE_SCHEME_V2, apkContentDigests, result);
                signatureSchemeApkContentDigests.put(VERSION_APK_SIGNATURE_SCHEME_V2, apkContentDigests);
            }
        }
        if (mMinSdkVersion < AndroidSdkVersion.N || signatureSchemeApkContentDigests.isEmpty()) {
            Map<ContentDigestAlgorithm, byte[]> apkContentDigests = getApkContentDigestFromV1SigningScheme(cdRecords, apk, zipSections, result);
            signatureSchemeApkContentDigests.put(VERSION_JAR_SIGNATURE_SCHEME, apkContentDigests);
        }
        ApkSigResult sourceStampResult = V2SourceStampVerifier.verify(apk, zipSections, sourceStampCertificateDigest, signatureSchemeApkContentDigests, mMinSdkVersion, mMaxSdkVersion);
        result.mergeFrom(sourceStampResult);
        return result;
    } catch (ApkFormatException | IOException | ZipFormatException e) {
        result.addVerificationError(ApkVerificationIssue.MALFORMED_APK, e);
    } catch (NoSuchAlgorithmException e) {
        result.addVerificationError(ApkVerificationIssue.UNEXPECTED_EXCEPTION, e);
    } catch (SignatureNotFoundException e) {
        result.addVerificationError(ApkVerificationIssue.SOURCE_STAMP_SIG_MISSING);
    }
    return result;
}
Also used : CentralDirectoryRecord(com.android.apksig.internal.zip.CentralDirectoryRecord) HashMap(java.util.HashMap) ApkSigResult(com.android.apksig.internal.apk.ApkSigResult) ZipFormatException(com.android.apksig.zip.ZipFormatException) IOException(java.io.IOException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) ApkSigResult(com.android.apksig.internal.apk.ApkSigResult) SignatureInfo(com.android.apksig.internal.apk.SignatureInfo) ApkFormatException(com.android.apksig.apk.ApkFormatException) SignatureNotFoundException(com.android.apksig.internal.apk.SignatureNotFoundException) ContentDigestAlgorithm(com.android.apksig.internal.apk.ContentDigestAlgorithm) HashMap(java.util.HashMap) Map(java.util.Map) EnumMap(java.util.EnumMap) EnumMap(java.util.EnumMap) ZipSections(com.android.apksig.zip.ZipSections)

Example 5 with ApkFormatException

use of com.android.apksig.apk.ApkFormatException in project apksig by venshine.

the class SourceStampVerifier method getApkContentDigestFromV1SigningScheme.

/**
 * Returns a mapping of the {@link ContentDigestAlgorithm} to the {@code byte[]} digest of the
 * V1 / jar signing META-INF/MANIFEST.MF; if this file is not found then an empty {@code Map} is
 * returned.
 *
 * <p>If any errors are encountered while parsing the V1 signers the provided {@code result}
 * will be updated to include a warning, but the source stamp verification can still proceed.
 */
private static Map<ContentDigestAlgorithm, byte[]> getApkContentDigestFromV1SigningScheme(List<CentralDirectoryRecord> cdRecords, DataSource apk, ZipSections zipSections, Result result) throws IOException, ApkFormatException {
    CentralDirectoryRecord manifestCdRecord = null;
    List<CentralDirectoryRecord> signatureBlockRecords = new ArrayList<>(1);
    Map<ContentDigestAlgorithm, byte[]> v1ContentDigest = new EnumMap<>(ContentDigestAlgorithm.class);
    for (CentralDirectoryRecord cdRecord : cdRecords) {
        String cdRecordName = cdRecord.getName();
        if (cdRecordName == null) {
            continue;
        }
        if (manifestCdRecord == null && MANIFEST_ENTRY_NAME.equals(cdRecordName)) {
            manifestCdRecord = cdRecord;
            continue;
        }
        if (cdRecordName.startsWith("META-INF/") && (cdRecordName.endsWith(".RSA") || cdRecordName.endsWith(".DSA") || cdRecordName.endsWith(".EC"))) {
            signatureBlockRecords.add(cdRecord);
        }
    }
    if (manifestCdRecord == null) {
        // thus an empty digest will invalidate that signature.
        return v1ContentDigest;
    }
    if (signatureBlockRecords.isEmpty()) {
        result.addVerificationWarning(ApkVerificationIssue.JAR_SIG_NO_SIGNATURES);
    } else {
        for (CentralDirectoryRecord signatureBlockRecord : signatureBlockRecords) {
            try {
                CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
                byte[] signatureBlockBytes = LocalFileRecord.getUncompressedData(apk, signatureBlockRecord, zipSections.getZipCentralDirectoryOffset());
                for (Certificate certificate : certFactory.generateCertificates(new ByteArrayInputStream(signatureBlockBytes))) {
                    // first is used as the signer of this block.
                    if (certificate instanceof X509Certificate) {
                        Result.SignerInfo signerInfo = new Result.SignerInfo();
                        signerInfo.setSigningCertificate((X509Certificate) certificate);
                        result.addV1Signer(signerInfo);
                        break;
                    }
                }
            } catch (CertificateException e) {
                // Log a warning for the parsing exception but still proceed with the stamp
                // verification.
                result.addVerificationWarning(ApkVerificationIssue.JAR_SIG_PARSE_EXCEPTION, signatureBlockRecord.getName(), e);
                break;
            } catch (ZipFormatException e) {
                throw new ApkFormatException("Failed to read APK", e);
            }
        }
    }
    try {
        byte[] manifestBytes = LocalFileRecord.getUncompressedData(apk, manifestCdRecord, zipSections.getZipCentralDirectoryOffset());
        v1ContentDigest.put(ContentDigestAlgorithm.SHA256, computeSha256DigestBytes(manifestBytes));
        return v1ContentDigest;
    } catch (ZipFormatException e) {
        throw new ApkFormatException("Failed to read APK", e);
    }
}
Also used : CentralDirectoryRecord(com.android.apksig.internal.zip.CentralDirectoryRecord) ArrayList(java.util.ArrayList) CertificateException(java.security.cert.CertificateException) ZipFormatException(com.android.apksig.zip.ZipFormatException) CertificateFactory(java.security.cert.CertificateFactory) X509Certificate(java.security.cert.X509Certificate) GuaranteedEncodedFormX509Certificate(com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate) ApkSigResult(com.android.apksig.internal.apk.ApkSigResult) ApkSignerInfo(com.android.apksig.internal.apk.ApkSignerInfo) ByteArrayInputStream(java.io.ByteArrayInputStream) ApkFormatException(com.android.apksig.apk.ApkFormatException) ContentDigestAlgorithm(com.android.apksig.internal.apk.ContentDigestAlgorithm) EnumMap(java.util.EnumMap) X509Certificate(java.security.cert.X509Certificate) GuaranteedEncodedFormX509Certificate(com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate) Certificate(java.security.cert.Certificate)

Aggregations

ApkFormatException (com.android.apksig.apk.ApkFormatException)36 IOException (java.io.IOException)18 ByteBuffer (java.nio.ByteBuffer)17 ArrayList (java.util.ArrayList)15 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)13 BufferUnderflowException (java.nio.BufferUnderflowException)12 ZipFormatException (com.android.apksig.zip.ZipFormatException)11 CertificateException (java.security.cert.CertificateException)11 ApkSigningBlockUtils (com.android.apksig.internal.apk.ApkSigningBlockUtils)9 CentralDirectoryRecord (com.android.apksig.internal.zip.CentralDirectoryRecord)9 X509Certificate (java.security.cert.X509Certificate)9 InvalidKeyException (java.security.InvalidKeyException)7 SignatureException (java.security.SignatureException)7 CertificateFactory (java.security.cert.CertificateFactory)7 SignatureAlgorithm (com.android.apksig.internal.apk.SignatureAlgorithm)6 GuaranteedEncodedFormX509Certificate (com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate)6 HashSet (java.util.HashSet)6 ApkSigResult (com.android.apksig.internal.apk.ApkSigResult)5 DataSource (com.android.apksig.util.DataSource)5 InvalidAlgorithmParameterException (java.security.InvalidAlgorithmParameterException)5