Search in sources :

Example 6 with Pair

use of com.android.apksig.internal.util.Pair in project LSPatch by LSPosed.

the class SigningBlockUtils method extractAllSigners.

/**
 * Extracts all signing block entries except padding block.
 *
 * @param signingBlock APK v2 signing block containing: length prefix, signers (can include
 *     padding block), length postfix and APK sig v2 block magic.
 * @return list of block entry value and block entry id pairs.
 */
private static ImmutableList<Pair<byte[], Integer>> extractAllSigners(DataSource signingBlock) throws IOException {
    long wholeBlockSize = signingBlock.size();
    // Take the segment of the existing signing block without the length prefix (8 bytes)
    // at the beginning and the length and magic (24 bytes) at the end, so it is just the sequence
    // of length prefix id value pairs.
    DataSource lengthPrefixedIdValuePairsSource = signingBlock.slice(SIZE_OF_BLOCK_NUM_BYTES, wholeBlockSize - 2 * SIZE_OF_BLOCK_NUM_BYTES - MAGIC_NUM_BYTES);
    final int lengthAndIdByteCount = BLOCK_LENGTH_NUM_BYTES + BLOCK_ID_NUM_BYTES;
    ByteBuffer lengthAndId = ByteBuffer.allocate(lengthAndIdByteCount).order(LITTLE_ENDIAN);
    ImmutableList.Builder<Pair<byte[], Integer>> idValuePairs = ImmutableList.builder();
    for (int index = 0; index <= lengthPrefixedIdValuePairsSource.size() - lengthAndIdByteCount; ) {
        lengthPrefixedIdValuePairsSource.copyTo(index, lengthAndIdByteCount, lengthAndId);
        lengthAndId.flip();
        int blockLength = Ints.checkedCast(lengthAndId.getLong());
        int id = lengthAndId.getInt();
        lengthAndId.clear();
        if (id != VERITY_PADDING_BLOCK_ID) {
            int blockValueSize = blockLength - BLOCK_ID_NUM_BYTES;
            ByteBuffer blockValue = ByteBuffer.allocate(blockValueSize);
            lengthPrefixedIdValuePairsSource.copyTo(index + BLOCK_LENGTH_NUM_BYTES + BLOCK_ID_NUM_BYTES, blockValueSize, blockValue);
            idValuePairs.add(Pair.of(blockValue.array(), id));
        }
        index += blockLength + BLOCK_LENGTH_NUM_BYTES;
    }
    return idValuePairs.build();
}
Also used : ImmutableList(com.google.common.collect.ImmutableList) ByteBuffer(java.nio.ByteBuffer) DataSource(com.android.apksig.util.DataSource) Pair(com.android.apksig.internal.util.Pair)

Example 7 with Pair

use of com.android.apksig.internal.util.Pair 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 8 with Pair

use of com.android.apksig.internal.util.Pair in project apksig by venshine.

the class DefaultApkSignerEngine method outputJarEntries.

@Override
public OutputJarSignatureRequest outputJarEntries() throws ApkFormatException, InvalidKeyException, SignatureException, NoSuchAlgorithmException {
    checkNotClosed();
    if (!mV1SignaturePending) {
        return null;
    }
    if ((mInputJarManifestEntryDataRequest != null) && (!mInputJarManifestEntryDataRequest.isDone())) {
        throw new IllegalStateException("Still waiting to inspect input APK's " + mInputJarManifestEntryDataRequest.getEntryName());
    }
    for (GetJarEntryDataDigestRequest digestRequest : mOutputJarEntryDigestRequests.values()) {
        String entryName = digestRequest.getEntryName();
        if (!digestRequest.isDone()) {
            throw new IllegalStateException("Still waiting to inspect output APK's " + entryName);
        }
        mOutputJarEntryDigests.put(entryName, digestRequest.getDigest());
    }
    if (isEligibleForSourceStamp()) {
        MessageDigest messageDigest = MessageDigest.getInstance(V1SchemeSigner.getJcaMessageDigestAlgorithm(mV1ContentDigestAlgorithm));
        messageDigest.update(generateSourceStampCertificateDigest());
        mOutputJarEntryDigests.put(SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME, messageDigest.digest());
    }
    mOutputJarEntryDigestRequests.clear();
    for (GetJarEntryDataRequest dataRequest : mOutputSignatureJarEntryDataRequests.values()) {
        if (!dataRequest.isDone()) {
            throw new IllegalStateException("Still waiting to inspect output APK's " + dataRequest.getEntryName());
        }
    }
    List<Integer> apkSigningSchemeIds = new ArrayList<>();
    if (mV2SigningEnabled) {
        apkSigningSchemeIds.add(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2);
    }
    if (mV3SigningEnabled) {
        apkSigningSchemeIds.add(ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3);
    }
    byte[] inputJarManifest = (mInputJarManifestEntryDataRequest != null) ? mInputJarManifestEntryDataRequest.getData() : null;
    if (isEligibleForSourceStamp()) {
        inputJarManifest = V1SchemeSigner.generateManifestFile(mV1ContentDigestAlgorithm, mOutputJarEntryDigests, inputJarManifest).contents;
    }
    // Check whether the most recently used signature (if present) is still fine.
    checkOutputApkNotDebuggableIfDebuggableMustBeRejected();
    List<Pair<String, byte[]>> signatureZipEntries;
    if ((mAddV1SignatureRequest == null) || (!mAddV1SignatureRequest.isDone())) {
        try {
            signatureZipEntries = V1SchemeSigner.sign(mV1SignerConfigs, mV1ContentDigestAlgorithm, mOutputJarEntryDigests, apkSigningSchemeIds, inputJarManifest, mCreatedBy);
        } catch (CertificateException e) {
            throw new SignatureException("Failed to generate v1 signature", e);
        }
    } else {
        V1SchemeSigner.OutputManifestFile newManifest = V1SchemeSigner.generateManifestFile(mV1ContentDigestAlgorithm, mOutputJarEntryDigests, inputJarManifest);
        byte[] emittedSignatureManifest = mEmittedSignatureJarEntryData.get(V1SchemeConstants.MANIFEST_ENTRY_NAME);
        if (!Arrays.equals(newManifest.contents, emittedSignatureManifest)) {
            // Emitted v1 signature is no longer valid.
            try {
                signatureZipEntries = V1SchemeSigner.signManifest(mV1SignerConfigs, mV1ContentDigestAlgorithm, apkSigningSchemeIds, mCreatedBy, newManifest);
            } catch (CertificateException e) {
                throw new SignatureException("Failed to generate v1 signature", e);
            }
        } else {
            // Emitted v1 signature is still valid. Check whether the signature is there in the
            // output.
            signatureZipEntries = new ArrayList<>();
            for (Map.Entry<String, byte[]> expectedOutputEntry : mEmittedSignatureJarEntryData.entrySet()) {
                String entryName = expectedOutputEntry.getKey();
                byte[] expectedData = expectedOutputEntry.getValue();
                GetJarEntryDataRequest actualDataRequest = mOutputSignatureJarEntryDataRequests.get(entryName);
                if (actualDataRequest == null) {
                    // This signature entry hasn't been output.
                    signatureZipEntries.add(Pair.of(entryName, expectedData));
                    continue;
                }
                byte[] actualData = actualDataRequest.getData();
                if (!Arrays.equals(expectedData, actualData)) {
                    signatureZipEntries.add(Pair.of(entryName, expectedData));
                }
            }
            if (signatureZipEntries.isEmpty()) {
                // v1 signature in the output is valid
                return null;
            }
        // v1 signature in the output is not valid.
        }
    }
    if (signatureZipEntries.isEmpty()) {
        // v1 signature in the output is valid
        mV1SignaturePending = false;
        return null;
    }
    List<OutputJarSignatureRequest.JarEntry> sigEntries = new ArrayList<>(signatureZipEntries.size());
    for (Pair<String, byte[]> entry : signatureZipEntries) {
        String entryName = entry.getFirst();
        byte[] entryData = entry.getSecond();
        sigEntries.add(new OutputJarSignatureRequest.JarEntry(entryName, entryData));
        mEmittedSignatureJarEntryData.put(entryName, entryData);
    }
    mAddV1SignatureRequest = new OutputJarSignatureRequestImpl(sigEntries);
    return mAddV1SignatureRequest;
}
Also used : ArrayList(java.util.ArrayList) CertificateException(java.security.cert.CertificateException) SignatureException(java.security.SignatureException) V1SchemeSigner(com.android.apksig.internal.apk.v1.V1SchemeSigner) MessageDigest(java.security.MessageDigest) Map(java.util.Map) HashMap(java.util.HashMap) Pair(com.android.apksig.internal.util.Pair)

Example 9 with Pair

use of com.android.apksig.internal.util.Pair in project apksig by venshine.

the class V3SchemeSigner method generateSignerBlock.

private static byte[] generateSignerBlock(SignerConfig signerConfig, Map<ContentDigestAlgorithm, byte[]> contentDigests) throws NoSuchAlgorithmException, InvalidKeyException, SignatureException {
    if (signerConfig.certificates.isEmpty()) {
        throw new SignatureException("No certificates configured for signer");
    }
    PublicKey publicKey = signerConfig.certificates.get(0).getPublicKey();
    byte[] encodedPublicKey = encodePublicKey(publicKey);
    V3SignatureSchemeBlock.SignedData signedData = new V3SignatureSchemeBlock.SignedData();
    try {
        signedData.certificates = encodeCertificates(signerConfig.certificates);
    } catch (CertificateEncodingException e) {
        throw new SignatureException("Failed to encode certificates", e);
    }
    List<Pair<Integer, byte[]>> digests = new ArrayList<>(signerConfig.signatureAlgorithms.size());
    for (SignatureAlgorithm signatureAlgorithm : signerConfig.signatureAlgorithms) {
        ContentDigestAlgorithm contentDigestAlgorithm = signatureAlgorithm.getContentDigestAlgorithm();
        byte[] contentDigest = contentDigests.get(contentDigestAlgorithm);
        if (contentDigest == null) {
            throw new RuntimeException(contentDigestAlgorithm + " content digest for " + signatureAlgorithm + " not computed");
        }
        digests.add(Pair.of(signatureAlgorithm.getId(), contentDigest));
    }
    signedData.digests = digests;
    signedData.minSdkVersion = signerConfig.minSdkVersion;
    signedData.maxSdkVersion = signerConfig.maxSdkVersion;
    signedData.additionalAttributes = generateAdditionalAttributes(signerConfig);
    V3SignatureSchemeBlock.Signer signer = new V3SignatureSchemeBlock.Signer();
    signer.signedData = encodeSignedData(signedData);
    signer.minSdkVersion = signerConfig.minSdkVersion;
    signer.maxSdkVersion = signerConfig.maxSdkVersion;
    signer.publicKey = encodedPublicKey;
    signer.signatures = ApkSigningBlockUtils.generateSignaturesOverData(signerConfig, signer.signedData);
    return encodeSigner(signer);
}
Also used : PublicKey(java.security.PublicKey) ApkSigningBlockUtils.encodePublicKey(com.android.apksig.internal.apk.ApkSigningBlockUtils.encodePublicKey) ArrayList(java.util.ArrayList) CertificateEncodingException(java.security.cert.CertificateEncodingException) SignatureAlgorithm(com.android.apksig.internal.apk.SignatureAlgorithm) SignatureException(java.security.SignatureException) ContentDigestAlgorithm(com.android.apksig.internal.apk.ContentDigestAlgorithm) Pair(com.android.apksig.internal.util.Pair)

Example 10 with Pair

use of com.android.apksig.internal.util.Pair in project apksig by venshine.

the class ApkSigningBlockUtils method getApkSignatureBlockSigners.

/**
 * Returns the individual APK signers within the provided {@code signatureBlock} in a {@code
 * List} of {@code Pair} instances where the first element is a {@code List} of {@link
 * X509Certificate}s and the second element is a byte array of the individual signer's block.
 *
 * <p>This method supports any signature block that adheres to the following format up to the
 * signing certificate(s):
 * <pre>
 * * length-prefixed sequence of length-prefixed signers
 *   * length-prefixed signed data
 *     * length-prefixed sequence of length-prefixed digests:
 *       * uint32: signature algorithm ID
 *       * length-prefixed bytes: digest of contents
 *     * length-prefixed sequence of certificates:
 *       * length-prefixed bytes: X.509 certificate (ASN.1 DER encoded).
 * </pre>
 *
 * <p>Note, this is a convenience method to obtain any signers from an existing signature block;
 * the signature of each signer will not be verified.
 *
 * @throws ApkFormatException if an error is encountered while parsing the provided {@code
 * signatureBlock}
 * @throws CertificateException if the signing certificate(s) within an individual signer block
 * cannot be parsed
 */
public static List<Pair<List<X509Certificate>, byte[]>> getApkSignatureBlockSigners(byte[] signatureBlock) throws ApkFormatException, CertificateException {
    ByteBuffer signatureBlockBuffer = ByteBuffer.wrap(signatureBlock);
    signatureBlockBuffer.order(ByteOrder.LITTLE_ENDIAN);
    ByteBuffer signersBuffer = getLengthPrefixedSlice(signatureBlockBuffer);
    List<Pair<List<X509Certificate>, byte[]>> signers = new ArrayList<>();
    while (signersBuffer.hasRemaining()) {
        // Parse the next signer block, save all of its bytes for the resulting List, and
        // rewind the buffer to allow the signing certificate(s) to be parsed.
        ByteBuffer signer = getLengthPrefixedSlice(signersBuffer);
        byte[] signerBytes = new byte[signer.remaining()];
        signer.get(signerBytes);
        signer.rewind();
        ByteBuffer signedData = getLengthPrefixedSlice(signer);
        // The first length prefixed slice is the sequence of digests which are not required
        // when obtaining the signing certificate(s).
        getLengthPrefixedSlice(signedData);
        ByteBuffer certificatesBuffer = getLengthPrefixedSlice(signedData);
        List<X509Certificate> certificates = new ArrayList<>();
        while (certificatesBuffer.hasRemaining()) {
            int certLength = certificatesBuffer.getInt();
            byte[] certBytes = new byte[certLength];
            if (certLength > certificatesBuffer.remaining()) {
                throw new IllegalArgumentException("Cert index " + (certificates.size() + 1) + " under signer index " + (signers.size() + 1) + " size out of range: " + certLength);
            }
            certificatesBuffer.get(certBytes);
            GuaranteedEncodedFormX509Certificate signerCert = new GuaranteedEncodedFormX509Certificate(X509CertificateUtils.generateCertificate(certBytes), certBytes);
            certificates.add(signerCert);
        }
        signers.add(Pair.of(certificates, signerBytes));
    }
    return signers;
}
Also used : GuaranteedEncodedFormX509Certificate(com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate) ArrayList(java.util.ArrayList) ByteBuffer(java.nio.ByteBuffer) X509Certificate(java.security.cert.X509Certificate) GuaranteedEncodedFormX509Certificate(com.android.apksig.internal.util.GuaranteedEncodedFormX509Certificate) Pair(com.android.apksig.internal.util.Pair)

Aggregations

Pair (com.android.apksig.internal.util.Pair)14 ArrayList (java.util.ArrayList)11 SignatureException (java.security.SignatureException)8 PublicKey (java.security.PublicKey)5 CertificateEncodingException (java.security.cert.CertificateEncodingException)5 ContentDigestAlgorithm (com.android.apksig.internal.apk.ContentDigestAlgorithm)4 ByteBuffer (java.nio.ByteBuffer)4 SignatureAlgorithm (com.android.apksig.internal.apk.SignatureAlgorithm)3 Map (java.util.Map)3 ApkSigningBlockUtils (com.android.apksig.internal.apk.ApkSigningBlockUtils)2 ApkSigningBlockUtils.encodePublicKey (com.android.apksig.internal.apk.ApkSigningBlockUtils.encodePublicKey)2 DataSource (com.android.apksig.util.DataSource)2 InvalidKeyException (java.security.InvalidKeyException)2 CertificateException (java.security.cert.CertificateException)2 X509Certificate (java.security.cert.X509Certificate)2 HashMap (java.util.HashMap)2 ApkFormatException (com.android.apksig.apk.ApkFormatException)1 ApkUtils (com.android.apksig.apk.ApkUtils)1 V1SchemeSigner (com.android.apksig.internal.apk.v1.V1SchemeSigner)1 V3SigningCertificateLineage (com.android.apksig.internal.apk.v3.V3SigningCertificateLineage)1