Search in sources :

Example 21 with ApkFormatException

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

the class ApkSigner method sign.

private void sign(DataSource inputApk, DataSink outputApkOut, DataSource outputApkIn) throws IOException, ApkFormatException, NoSuchAlgorithmException, InvalidKeyException, SignatureException {
    // Step 1. Find input APK's main ZIP sections
    ApkUtils.ZipSections inputZipSections;
    try {
        inputZipSections = ApkUtils.findZipSections(inputApk);
    } catch (ZipFormatException e) {
        throw new ApkFormatException("Malformed APK: not a ZIP archive", e);
    }
    long inputApkSigningBlockOffset = -1;
    DataSource inputApkSigningBlock = null;
    try {
        ApkUtils.ApkSigningBlock apkSigningBlockInfo = ApkUtils.findApkSigningBlock(inputApk, inputZipSections);
        inputApkSigningBlockOffset = apkSigningBlockInfo.getStartOffset();
        inputApkSigningBlock = apkSigningBlockInfo.getContents();
    } catch (ApkSigningBlockNotFoundException e) {
    // Input APK does not contain an APK Signing Block. That's OK. APKs are not required to
    // contain this block. It's only needed if the APK is signed using APK Signature Scheme
    // v2 and/or v3.
    }
    DataSource inputApkLfhSection = inputApk.slice(0, (inputApkSigningBlockOffset != -1) ? inputApkSigningBlockOffset : inputZipSections.getZipCentralDirectoryOffset());
    // Step 2. Parse the input APK's ZIP Central Directory
    ByteBuffer inputCd = getZipCentralDirectory(inputApk, inputZipSections);
    List<CentralDirectoryRecord> inputCdRecords = parseZipCentralDirectory(inputCd, inputZipSections);
    List<Hints.PatternWithRange> pinPatterns = extractPinPatterns(inputCdRecords, inputApkLfhSection);
    List<Hints.ByteRange> pinByteRanges = pinPatterns == null ? null : new ArrayList<>();
    // Step 3. Obtain a signer engine instance
    ApkSignerEngine signerEngine;
    if (mSignerEngine != null) {
        // Use the provided signer engine
        signerEngine = mSignerEngine;
    } else {
        // Construct a signer engine from the provided parameters
        int minSdkVersion;
        if (mMinSdkVersion != null) {
            // No need to extract minSdkVersion from the APK's AndroidManifest.xml
            minSdkVersion = mMinSdkVersion;
        } else {
            // Need to extract minSdkVersion from the APK's AndroidManifest.xml
            minSdkVersion = getMinSdkVersionFromApk(inputCdRecords, inputApkLfhSection);
        }
        List<DefaultApkSignerEngine.SignerConfig> engineSignerConfigs = new ArrayList<>(mSignerConfigs.size());
        for (SignerConfig signerConfig : mSignerConfigs) {
            engineSignerConfigs.add(new DefaultApkSignerEngine.SignerConfig.Builder(signerConfig.getName(), signerConfig.getPrivateKey(), signerConfig.getCertificates(), signerConfig.getDeterministicDsaSigning()).build());
        }
        DefaultApkSignerEngine.Builder signerEngineBuilder = new DefaultApkSignerEngine.Builder(engineSignerConfigs, minSdkVersion).setV1SigningEnabled(mV1SigningEnabled).setV2SigningEnabled(mV2SigningEnabled).setV3SigningEnabled(mV3SigningEnabled).setVerityEnabled(mVerityEnabled).setDebuggableApkPermitted(mDebuggableApkPermitted).setOtherSignersSignaturesPreserved(mOtherSignersSignaturesPreserved).setSigningCertificateLineage(mSigningCertificateLineage);
        if (mCreatedBy != null) {
            signerEngineBuilder.setCreatedBy(mCreatedBy);
        }
        if (mSourceStampSignerConfig != null) {
            signerEngineBuilder.setStampSignerConfig(new DefaultApkSignerEngine.SignerConfig.Builder(mSourceStampSignerConfig.getName(), mSourceStampSignerConfig.getPrivateKey(), mSourceStampSignerConfig.getCertificates(), mSourceStampSignerConfig.getDeterministicDsaSigning()).build());
        }
        if (mSourceStampSigningCertificateLineage != null) {
            signerEngineBuilder.setSourceStampSigningCertificateLineage(mSourceStampSigningCertificateLineage);
        }
        signerEngine = signerEngineBuilder.build();
    }
    // Step 4. Provide the signer engine with the input APK's APK Signing Block (if any)
    if (inputApkSigningBlock != null) {
        signerEngine.inputApkSigningBlock(inputApkSigningBlock);
    }
    // Step 5. Iterate over input APK's entries and output the Local File Header + data of those
    // entries which need to be output. Entries are iterated in the order in which their Local
    // File Header records are stored in the file. This is to achieve better data locality in
    // case Central Directory entries are in the wrong order.
    List<CentralDirectoryRecord> inputCdRecordsSortedByLfhOffset = new ArrayList<>(inputCdRecords);
    Collections.sort(inputCdRecordsSortedByLfhOffset, CentralDirectoryRecord.BY_LOCAL_FILE_HEADER_OFFSET_COMPARATOR);
    int lastModifiedDateForNewEntries = -1;
    int lastModifiedTimeForNewEntries = -1;
    long inputOffset = 0;
    long outputOffset = 0;
    byte[] sourceStampCertificateDigest = null;
    Map<String, CentralDirectoryRecord> outputCdRecordsByName = new HashMap<>(inputCdRecords.size());
    for (final CentralDirectoryRecord inputCdRecord : inputCdRecordsSortedByLfhOffset) {
        String entryName = inputCdRecord.getName();
        if (Hints.PIN_BYTE_RANGE_ZIP_ENTRY_NAME.equals(entryName)) {
            // We'll re-add below if needed.
            continue;
        }
        if (SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME.equals(entryName)) {
            try {
                sourceStampCertificateDigest = LocalFileRecord.getUncompressedData(inputApkLfhSection, inputCdRecord, inputApkLfhSection.size());
            } catch (ZipFormatException ex) {
                throw new ApkFormatException("Bad source stamp entry");
            }
            // Existing source stamp is handled below as needed.
            continue;
        }
        ApkSignerEngine.InputJarEntryInstructions entryInstructions = signerEngine.inputJarEntry(entryName);
        boolean shouldOutput;
        switch(entryInstructions.getOutputPolicy()) {
            case OUTPUT:
                shouldOutput = true;
                break;
            case OUTPUT_BY_ENGINE:
            case SKIP:
                shouldOutput = false;
                break;
            default:
                throw new RuntimeException("Unknown output policy: " + entryInstructions.getOutputPolicy());
        }
        long inputLocalFileHeaderStartOffset = inputCdRecord.getLocalFileHeaderOffset();
        if (inputLocalFileHeaderStartOffset > inputOffset) {
            // Unprocessed data in input starting at inputOffset and ending and the start of
            // this record's LFH. We output this data verbatim because this signer is supposed
            // to preserve as much of input as possible.
            long chunkSize = inputLocalFileHeaderStartOffset - inputOffset;
            inputApkLfhSection.feed(inputOffset, chunkSize, outputApkOut);
            outputOffset += chunkSize;
            inputOffset = inputLocalFileHeaderStartOffset;
        }
        LocalFileRecord inputLocalFileRecord;
        try {
            inputLocalFileRecord = LocalFileRecord.getRecord(inputApkLfhSection, inputCdRecord, inputApkLfhSection.size());
        } catch (ZipFormatException e) {
            throw new ApkFormatException("Malformed ZIP entry: " + inputCdRecord.getName(), e);
        }
        inputOffset += inputLocalFileRecord.getSize();
        ApkSignerEngine.InspectJarEntryRequest inspectEntryRequest = entryInstructions.getInspectJarEntryRequest();
        if (inspectEntryRequest != null) {
            fulfillInspectInputJarEntryRequest(inputApkLfhSection, inputLocalFileRecord, inspectEntryRequest);
        }
        if (shouldOutput) {
            // Find the max value of last modified, to be used for new entries added by the
            // signer.
            int lastModifiedDate = inputCdRecord.getLastModificationDate();
            int lastModifiedTime = inputCdRecord.getLastModificationTime();
            if ((lastModifiedDateForNewEntries == -1) || (lastModifiedDate > lastModifiedDateForNewEntries) || ((lastModifiedDate == lastModifiedDateForNewEntries) && (lastModifiedTime > lastModifiedTimeForNewEntries))) {
                lastModifiedDateForNewEntries = lastModifiedDate;
                lastModifiedTimeForNewEntries = lastModifiedTime;
            }
            inspectEntryRequest = signerEngine.outputJarEntry(entryName);
            if (inspectEntryRequest != null) {
                fulfillInspectInputJarEntryRequest(inputApkLfhSection, inputLocalFileRecord, inspectEntryRequest);
            }
            // Output entry's Local File Header + data
            long outputLocalFileHeaderOffset = outputOffset;
            OutputSizeAndDataOffset outputLfrResult = outputInputJarEntryLfhRecordPreservingDataAlignment(inputApkLfhSection, inputLocalFileRecord, outputApkOut, outputLocalFileHeaderOffset);
            outputOffset += outputLfrResult.outputBytes;
            long outputDataOffset = outputLocalFileHeaderOffset + outputLfrResult.dataOffsetBytes;
            if (pinPatterns != null) {
                boolean pinFileHeader = false;
                for (Hints.PatternWithRange pinPattern : pinPatterns) {
                    if (pinPattern.matcher(inputCdRecord.getName()).matches()) {
                        Hints.ByteRange dataRange = new Hints.ByteRange(outputDataOffset, outputOffset);
                        Hints.ByteRange pinRange = pinPattern.ClampToAbsoluteByteRange(dataRange);
                        if (pinRange != null) {
                            pinFileHeader = true;
                            pinByteRanges.add(pinRange);
                        }
                    }
                }
                if (pinFileHeader) {
                    pinByteRanges.add(new Hints.ByteRange(outputLocalFileHeaderOffset, outputDataOffset));
                }
            }
            // Enqueue entry's Central Directory record for output
            CentralDirectoryRecord outputCdRecord;
            if (outputLocalFileHeaderOffset == inputLocalFileRecord.getStartOffsetInArchive()) {
                outputCdRecord = inputCdRecord;
            } else {
                outputCdRecord = inputCdRecord.createWithModifiedLocalFileHeaderOffset(outputLocalFileHeaderOffset);
            }
            outputCdRecordsByName.put(entryName, outputCdRecord);
        }
    }
    long inputLfhSectionSize = inputApkLfhSection.size();
    if (inputOffset < inputLfhSectionSize) {
        // Unprocessed data in input starting at inputOffset and ending and the end of the input
        // APK's LFH section. We output this data verbatim because this signer is supposed
        // to preserve as much of input as possible.
        long chunkSize = inputLfhSectionSize - inputOffset;
        inputApkLfhSection.feed(inputOffset, chunkSize, outputApkOut);
        outputOffset += chunkSize;
        inputOffset = inputLfhSectionSize;
    }
    // Step 6. Sort output APK's Central Directory records in the order in which they should
    // appear in the output
    List<CentralDirectoryRecord> outputCdRecords = new ArrayList<>(inputCdRecords.size() + 10);
    for (CentralDirectoryRecord inputCdRecord : inputCdRecords) {
        String entryName = inputCdRecord.getName();
        CentralDirectoryRecord outputCdRecord = outputCdRecordsByName.get(entryName);
        if (outputCdRecord != null) {
            outputCdRecords.add(outputCdRecord);
        }
    }
    if (lastModifiedDateForNewEntries == -1) {
        // Jan 1 2009 (DOS)
        lastModifiedDateForNewEntries = 0x3a21;
        lastModifiedTimeForNewEntries = 0;
    }
    // records.
    if (signerEngine.isEligibleForSourceStamp()) {
        byte[] uncompressedData = signerEngine.generateSourceStampCertificateDigest();
        if (mForceSourceStampOverwrite || sourceStampCertificateDigest == null || Arrays.equals(uncompressedData, sourceStampCertificateDigest)) {
            outputOffset += outputDataToOutputApk(SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME, uncompressedData, outputOffset, outputCdRecords, lastModifiedTimeForNewEntries, lastModifiedDateForNewEntries, outputApkOut);
        } else {
            throw new ApkFormatException(String.format("Cannot generate SourceStamp. APK contains an existing entry with" + " the name: %s, and it is different than the provided source" + " stamp certificate", SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME));
        }
    }
    // This has to be before the step 8 so that the file is signed.
    if (pinByteRanges != null) {
        // Covers JAR signature and zip central dir entry.
        // The signature files don't have to be pinned, but pinning them isn't that wasteful
        // since the total size is small.
        pinByteRanges.add(new Hints.ByteRange(outputOffset, Long.MAX_VALUE));
        String entryName = Hints.PIN_BYTE_RANGE_ZIP_ENTRY_NAME;
        byte[] uncompressedData = Hints.encodeByteRangeList(pinByteRanges);
        requestOutputEntryInspection(signerEngine, entryName, uncompressedData);
        outputOffset += outputDataToOutputApk(entryName, uncompressedData, outputOffset, outputCdRecords, lastModifiedTimeForNewEntries, lastModifiedDateForNewEntries, outputApkOut);
    }
    // Step 8. Generate and output JAR signatures, if necessary. This may output more Local File
    // Header + data entries and add to the list of output Central Directory records.
    ApkSignerEngine.OutputJarSignatureRequest outputJarSignatureRequest = signerEngine.outputJarEntries();
    if (outputJarSignatureRequest != null) {
        for (ApkSignerEngine.OutputJarSignatureRequest.JarEntry entry : outputJarSignatureRequest.getAdditionalJarEntries()) {
            String entryName = entry.getName();
            byte[] uncompressedData = entry.getData();
            requestOutputEntryInspection(signerEngine, entryName, uncompressedData);
            outputOffset += outputDataToOutputApk(entryName, uncompressedData, outputOffset, outputCdRecords, lastModifiedTimeForNewEntries, lastModifiedDateForNewEntries, outputApkOut);
        }
        outputJarSignatureRequest.done();
    }
    // Step 9. Construct output ZIP Central Directory in an in-memory buffer
    long outputCentralDirSizeBytes = 0;
    for (CentralDirectoryRecord record : outputCdRecords) {
        outputCentralDirSizeBytes += record.getSize();
    }
    if (outputCentralDirSizeBytes > Integer.MAX_VALUE) {
        throw new IOException("Output ZIP Central Directory too large: " + outputCentralDirSizeBytes + " bytes");
    }
    ByteBuffer outputCentralDir = ByteBuffer.allocate((int) outputCentralDirSizeBytes);
    for (CentralDirectoryRecord record : outputCdRecords) {
        record.copyTo(outputCentralDir);
    }
    outputCentralDir.flip();
    DataSource outputCentralDirDataSource = new ByteBufferDataSource(outputCentralDir);
    long outputCentralDirStartOffset = outputOffset;
    int outputCentralDirRecordCount = outputCdRecords.size();
    // Step 10. Construct output ZIP End of Central Directory record in an in-memory buffer
    ByteBuffer outputEocd = EocdRecord.createWithModifiedCentralDirectoryInfo(inputZipSections.getZipEndOfCentralDirectory(), outputCentralDirRecordCount, outputCentralDirDataSource.size(), outputCentralDirStartOffset);
    // Step 11. Generate and output APK Signature Scheme v2 and/or v3 signatures and/or
    // SourceStamp signatures, if necessary.
    // This may insert an APK Signing Block just before the output's ZIP Central Directory
    ApkSignerEngine.OutputApkSigningBlockRequest2 outputApkSigningBlockRequest = signerEngine.outputZipSections2(outputApkIn, outputCentralDirDataSource, DataSources.asDataSource(outputEocd));
    if (outputApkSigningBlockRequest != null) {
        int padding = outputApkSigningBlockRequest.getPaddingSizeBeforeApkSigningBlock();
        outputApkOut.consume(ByteBuffer.allocate(padding));
        byte[] outputApkSigningBlock = outputApkSigningBlockRequest.getApkSigningBlock();
        outputApkOut.consume(outputApkSigningBlock, 0, outputApkSigningBlock.length);
        ZipUtils.setZipEocdCentralDirectoryOffset(outputEocd, outputCentralDirStartOffset + padding + outputApkSigningBlock.length);
        outputApkSigningBlockRequest.done();
    }
    // Step 12. Output ZIP Central Directory and ZIP End of Central Directory
    outputCentralDirDataSource.feed(0, outputCentralDirDataSource.size(), outputApkOut);
    outputApkOut.consume(outputEocd);
    signerEngine.outputDone();
    // Step 13. Generate and output APK Signature Scheme v4 signatures, if necessary.
    if (mV4SigningEnabled) {
        signerEngine.signV4(outputApkIn, mOutputV4File, !mV4ErrorReportingEnabled);
    }
}
Also used : CentralDirectoryRecord(com.android.apksig.internal.zip.CentralDirectoryRecord) HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ZipFormatException(com.android.apksig.zip.ZipFormatException) ApkFormatException(com.android.apksig.apk.ApkFormatException) ByteBufferDataSource(com.android.apksig.internal.util.ByteBufferDataSource) IOException(java.io.IOException) ByteBuffer(java.nio.ByteBuffer) DataSource(com.android.apksig.util.DataSource) ByteBufferDataSource(com.android.apksig.internal.util.ByteBufferDataSource) LocalFileRecord(com.android.apksig.internal.zip.LocalFileRecord) ApkUtils(com.android.apksig.apk.ApkUtils) ApkSigningBlockNotFoundException(com.android.apksig.apk.ApkSigningBlockNotFoundException)

Example 22 with ApkFormatException

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

the class ApkSignerTool method getLineageFromInputFile.

/**
 * Extracts the Signing Certificate Lineage from the provided lineage or APK file.
 */
private static SigningCertificateLineage getLineageFromInputFile(File inputLineageFile) throws ParameterException {
    try (RandomAccessFile f = new RandomAccessFile(inputLineageFile, "r")) {
        if (f.length() < 4) {
            throw new ParameterException("The input file is not a valid lineage file.");
        }
        DataSource apk = DataSources.asDataSource(f);
        int magicValue = apk.getByteBuffer(0, 4).order(ByteOrder.LITTLE_ENDIAN).getInt();
        if (magicValue == SigningCertificateLineage.MAGIC) {
            return SigningCertificateLineage.readFromFile(inputLineageFile);
        } else if (magicValue == ZIP_MAGIC) {
            return SigningCertificateLineage.readFromApkFile(inputLineageFile);
        } else {
            throw new ParameterException("The input file is not a valid lineage file.");
        }
    } catch (IOException | ApkFormatException | IllegalArgumentException e) {
        throw new ParameterException(e.getMessage());
    }
}
Also used : RandomAccessFile(java.io.RandomAccessFile) ApkFormatException(com.android.apksig.apk.ApkFormatException) IOException(java.io.IOException) DataSource(com.android.apksig.util.DataSource)

Example 23 with ApkFormatException

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

the class ZipUtils method parseZipCentralDirectory.

public static List<CentralDirectoryRecord> parseZipCentralDirectory(DataSource apk, ZipSections apkSections) throws IOException, ApkFormatException {
    // Read the ZIP Central Directory
    long cdSizeBytes = apkSections.getZipCentralDirectorySizeBytes();
    if (cdSizeBytes > Integer.MAX_VALUE) {
        throw new ApkFormatException("ZIP Central Directory too large: " + cdSizeBytes);
    }
    long cdOffset = apkSections.getZipCentralDirectoryOffset();
    ByteBuffer cd = apk.getByteBuffer(cdOffset, (int) cdSizeBytes);
    cd.order(ByteOrder.LITTLE_ENDIAN);
    // Parse the ZIP Central Directory
    int expectedCdRecordCount = apkSections.getZipCentralDirectoryRecordCount();
    List<CentralDirectoryRecord> cdRecords = new ArrayList<>(expectedCdRecordCount);
    for (int i = 0; i < expectedCdRecordCount; i++) {
        CentralDirectoryRecord cdRecord;
        int offsetInsideCd = cd.position();
        try {
            cdRecord = CentralDirectoryRecord.getRecord(cd);
        } catch (ZipFormatException e) {
            throw new ApkFormatException("Malformed ZIP Central Directory record #" + (i + 1) + " at file offset " + (cdOffset + offsetInsideCd), e);
        }
        String entryName = cdRecord.getName();
        if (entryName.endsWith("/")) {
            // Ignore directory entries
            continue;
        }
        cdRecords.add(cdRecord);
    }
    return cdRecords;
}
Also used : ApkFormatException(com.android.apksig.apk.ApkFormatException) ArrayList(java.util.ArrayList) ZipFormatException(com.android.apksig.zip.ZipFormatException) ByteBuffer(java.nio.ByteBuffer)

Example 24 with ApkFormatException

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

the class DefaultApkSignerEngine method outputZipSectionsInternal.

private OutputApkSigningBlockRequestImpl outputZipSectionsInternal(DataSource zipEntries, DataSource zipCentralDirectory, DataSource zipEocd, boolean apkSigningBlockPaddingSupported) throws IOException, InvalidKeyException, SignatureException, NoSuchAlgorithmException {
    checkNotClosed();
    checkV1SigningDoneIfEnabled();
    if (!mV2SigningEnabled && !mV3SigningEnabled && !isEligibleForSourceStamp()) {
        return null;
    }
    checkOutputApkNotDebuggableIfDebuggableMustBeRejected();
    // adjust to proper padding
    Pair<DataSource, Integer> paddingPair = ApkSigningBlockUtils.generateApkSigningBlockPadding(zipEntries, apkSigningBlockPaddingSupported);
    DataSource beforeCentralDir = paddingPair.getFirst();
    int padSizeBeforeApkSigningBlock = paddingPair.getSecond();
    DataSource eocd = ApkSigningBlockUtils.copyWithModifiedCDOffset(beforeCentralDir, zipEocd);
    List<Pair<byte[], Integer>> signingSchemeBlocks = new ArrayList<>();
    ApkSigningBlockUtils.SigningSchemeBlockAndDigests v2SigningSchemeBlockAndDigests = null;
    ApkSigningBlockUtils.SigningSchemeBlockAndDigests v3SigningSchemeBlockAndDigests = null;
    // new APK signing block.
    if (mOtherSignersSignaturesPreserved && mPreservedSignatureBlocks != null && !mPreservedSignatureBlocks.isEmpty()) {
        signingSchemeBlocks.addAll(mPreservedSignatureBlocks);
    }
    // create APK Signature Scheme V2 Signature if requested
    if (mV2SigningEnabled) {
        invalidateV2Signature();
        List<ApkSigningBlockUtils.SignerConfig> v2SignerConfigs = createV2SignerConfigs(apkSigningBlockPaddingSupported);
        v2SigningSchemeBlockAndDigests = V2SchemeSigner.generateApkSignatureSchemeV2Block(mExecutor, beforeCentralDir, zipCentralDirectory, eocd, v2SignerConfigs, mV3SigningEnabled, mOtherSignersSignaturesPreserved ? mPreservedV2Signers : null);
        signingSchemeBlocks.add(v2SigningSchemeBlockAndDigests.signingSchemeBlock);
    }
    if (mV3SigningEnabled) {
        invalidateV3Signature();
        List<ApkSigningBlockUtils.SignerConfig> v3SignerConfigs = createV3SignerConfigs(apkSigningBlockPaddingSupported);
        v3SigningSchemeBlockAndDigests = V3SchemeSigner.generateApkSignatureSchemeV3Block(mExecutor, beforeCentralDir, zipCentralDirectory, eocd, v3SignerConfigs);
        signingSchemeBlocks.add(v3SigningSchemeBlockAndDigests.signingSchemeBlock);
    }
    if (isEligibleForSourceStamp()) {
        ApkSigningBlockUtils.SignerConfig sourceStampSignerConfig = createSourceStampSignerConfig();
        Map<Integer, Map<ContentDigestAlgorithm, byte[]>> signatureSchemeDigestInfos = new HashMap<>();
        if (mV3SigningEnabled) {
            signatureSchemeDigestInfos.put(VERSION_APK_SIGNATURE_SCHEME_V3, v3SigningSchemeBlockAndDigests.digestInfo);
        }
        if (mV2SigningEnabled) {
            signatureSchemeDigestInfos.put(VERSION_APK_SIGNATURE_SCHEME_V2, v2SigningSchemeBlockAndDigests.digestInfo);
        }
        if (mV1SigningEnabled) {
            Map<ContentDigestAlgorithm, byte[]> v1SigningSchemeDigests = new HashMap<>();
            try {
                // Jar signing related variables must have been already populated at this point
                // if V1 signing is enabled since it is happening before computations on the APK
                // signing block (V2/V3/V4/SourceStamp signing).
                byte[] inputJarManifest = (mInputJarManifestEntryDataRequest != null) ? mInputJarManifestEntryDataRequest.getData() : null;
                byte[] jarManifest = V1SchemeSigner.generateManifestFile(mV1ContentDigestAlgorithm, mOutputJarEntryDigests, inputJarManifest).contents;
                // The digest of the jar manifest does not need to be computed in chunks due to
                // the small size of the manifest.
                v1SigningSchemeDigests.put(ContentDigestAlgorithm.SHA256, computeSha256DigestBytes(jarManifest));
            } catch (ApkFormatException e) {
                throw new RuntimeException("Failed to generate manifest file", e);
            }
            signatureSchemeDigestInfos.put(VERSION_JAR_SIGNATURE_SCHEME, v1SigningSchemeDigests);
        }
        signingSchemeBlocks.add(V2SourceStampSigner.generateSourceStampBlock(sourceStampSignerConfig, signatureSchemeDigestInfos));
    }
    // create APK Signing Block with v2 and/or v3 and/or SourceStamp blocks
    byte[] apkSigningBlock = ApkSigningBlockUtils.generateApkSigningBlock(signingSchemeBlocks);
    mAddSigningBlockRequest = new OutputApkSigningBlockRequestImpl(apkSigningBlock, padSizeBeforeApkSigningBlock);
    return mAddSigningBlockRequest;
}
Also used : HashMap(java.util.HashMap) ArrayList(java.util.ArrayList) ApkSigningBlockUtils(com.android.apksig.internal.apk.ApkSigningBlockUtils) DataSource(com.android.apksig.util.DataSource) ApkFormatException(com.android.apksig.apk.ApkFormatException) ContentDigestAlgorithm(com.android.apksig.internal.apk.ContentDigestAlgorithm) Map(java.util.Map) HashMap(java.util.HashMap) Pair(com.android.apksig.internal.util.Pair)

Example 25 with ApkFormatException

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

the class SigningCertificateLineage method readFromApkDataSource.

/**
 * Extracts a Signing Certificate Lineage from the proof-of-rotation attribute in the V3
 * signature block of the provided APK DataSource.
 *
 * @throws IllegalArgumentException if the provided APK does not contain a V3 signature block,
 * or if the V3 signature block does not contain a valid lineage.
 */
public static SigningCertificateLineage readFromApkDataSource(DataSource apk) throws IOException, ApkFormatException {
    SignatureInfo signatureInfo;
    try {
        ApkUtils.ZipSections zipSections = ApkUtils.findZipSections(apk);
        ApkSigningBlockUtils.Result result = new ApkSigningBlockUtils.Result(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3);
        signatureInfo = ApkSigningBlockUtils.findSignature(apk, zipSections, V3SchemeConstants.APK_SIGNATURE_SCHEME_V3_BLOCK_ID, result);
    } catch (ZipFormatException e) {
        throw new ApkFormatException(e.getMessage());
    } catch (ApkSigningBlockUtils.SignatureNotFoundException e) {
        throw new IllegalArgumentException("The provided APK does not contain a valid V3 signature block.");
    }
    // FORMAT:
    // * length-prefixed sequence of length-prefixed signers:
    // * length-prefixed signed data
    // * minSDK
    // * maxSDK
    // * length-prefixed sequence of length-prefixed signatures
    // * length-prefixed public key
    ByteBuffer signers = getLengthPrefixedSlice(signatureInfo.signatureBlock);
    List<SigningCertificateLineage> lineages = new ArrayList<>(1);
    while (signers.hasRemaining()) {
        ByteBuffer signer = getLengthPrefixedSlice(signers);
        ByteBuffer signedData = getLengthPrefixedSlice(signer);
        try {
            SigningCertificateLineage lineage = readFromSignedData(signedData);
            lineages.add(lineage);
        } catch (IllegalArgumentException ignored) {
        // The current signer block does not contain a valid lineage, but it is possible
        // another block will.
        }
    }
    SigningCertificateLineage result;
    if (lineages.isEmpty()) {
        throw new IllegalArgumentException("The provided APK does not contain a valid lineage.");
    } else if (lineages.size() > 1) {
        result = consolidateLineages(lineages);
    } else {
        result = lineages.get(0);
    }
    return result;
}
Also used : ArrayList(java.util.ArrayList) ZipFormatException(com.android.apksig.zip.ZipFormatException) ApkSigningBlockUtils(com.android.apksig.internal.apk.ApkSigningBlockUtils) ByteBuffer(java.nio.ByteBuffer) SignatureInfo(com.android.apksig.internal.apk.SignatureInfo) V3SigningCertificateLineage(com.android.apksig.internal.apk.v3.V3SigningCertificateLineage) ApkUtils(com.android.apksig.apk.ApkUtils) ApkFormatException(com.android.apksig.apk.ApkFormatException)

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