Search in sources :

Example 1 with ZipSections

use of com.android.apksig.zip.ZipSections 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 2 with ZipSections

use of com.android.apksig.zip.ZipSections in project apksig by venshine.

the class ApkUtilsLite method findZipSections.

/**
 * Finds the main ZIP sections of the provided APK.
 *
 * @throws IOException if an I/O error occurred while reading the APK
 * @throws ZipFormatException if the APK is malformed
 */
public static ZipSections findZipSections(DataSource apk) throws IOException, ZipFormatException {
    Pair<ByteBuffer, Long> eocdAndOffsetInFile = ZipUtils.findZipEndOfCentralDirectoryRecord(apk);
    if (eocdAndOffsetInFile == null) {
        throw new ZipFormatException("ZIP End of Central Directory record not found");
    }
    ByteBuffer eocdBuf = eocdAndOffsetInFile.getFirst();
    long eocdOffset = eocdAndOffsetInFile.getSecond();
    eocdBuf.order(ByteOrder.LITTLE_ENDIAN);
    long cdStartOffset = ZipUtils.getZipEocdCentralDirectoryOffset(eocdBuf);
    if (cdStartOffset > eocdOffset) {
        throw new ZipFormatException("ZIP Central Directory start offset out of range: " + cdStartOffset + ". ZIP End of Central Directory offset: " + eocdOffset);
    }
    long cdSizeBytes = ZipUtils.getZipEocdCentralDirectorySizeBytes(eocdBuf);
    long cdEndOffset = cdStartOffset + cdSizeBytes;
    if (cdEndOffset > eocdOffset) {
        throw new ZipFormatException("ZIP Central Directory overlaps with End of Central Directory" + ". CD end: " + cdEndOffset + ", EoCD start: " + eocdOffset);
    }
    int cdRecordCount = ZipUtils.getZipEocdCentralDirectoryTotalRecordCount(eocdBuf);
    return new ZipSections(cdStartOffset, cdSizeBytes, cdRecordCount, eocdOffset, eocdBuf);
}
Also used : ZipFormatException(com.android.apksig.zip.ZipFormatException) ByteBuffer(java.nio.ByteBuffer) ZipSections(com.android.apksig.zip.ZipSections)

Aggregations

ZipFormatException (com.android.apksig.zip.ZipFormatException)2 ZipSections (com.android.apksig.zip.ZipSections)2 ApkFormatException (com.android.apksig.apk.ApkFormatException)1 ApkSigResult (com.android.apksig.internal.apk.ApkSigResult)1 ContentDigestAlgorithm (com.android.apksig.internal.apk.ContentDigestAlgorithm)1 SignatureInfo (com.android.apksig.internal.apk.SignatureInfo)1 SignatureNotFoundException (com.android.apksig.internal.apk.SignatureNotFoundException)1 CentralDirectoryRecord (com.android.apksig.internal.zip.CentralDirectoryRecord)1 IOException (java.io.IOException)1 ByteBuffer (java.nio.ByteBuffer)1 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)1 EnumMap (java.util.EnumMap)1 HashMap (java.util.HashMap)1 Map (java.util.Map)1