Search in sources :

Example 1 with SignatureInfo

use of com.android.apksig.internal.apk.SignatureInfo 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 SignatureInfo

use of com.android.apksig.internal.apk.SignatureInfo in project apksig by venshine.

the class V2SourceStampVerifier method verify.

/**
 * Verifies the provided APK's SourceStamp signatures and returns the result of verification.
 * The APK must be considered verified only if {@link ApkSigResult#verified} is
 * {@code true}. If verification fails, the result will contain errors -- see {@link
 * ApkSigResult#getErrors()}.
 *
 * @throws NoSuchAlgorithmException if the APK's signatures cannot be verified because a
 *     required cryptographic algorithm implementation is missing
 * @throws SignatureNotFoundException if no SourceStamp signatures are
 *     found
 * @throws IOException if an I/O error occurs when reading the APK
 */
public static ApkSigResult verify(DataSource apk, ZipSections zipSections, byte[] sourceStampCertificateDigest, Map<Integer, Map<ContentDigestAlgorithm, byte[]>> signatureSchemeApkContentDigests, int minSdkVersion, int maxSdkVersion) throws IOException, NoSuchAlgorithmException, SignatureNotFoundException {
    ApkSigResult result = new ApkSigResult(Constants.VERSION_SOURCE_STAMP);
    SignatureInfo signatureInfo = ApkSigningBlockUtilsLite.findSignature(apk, zipSections, V2_SOURCE_STAMP_BLOCK_ID);
    verify(signatureInfo.signatureBlock, sourceStampCertificateDigest, signatureSchemeApkContentDigests, minSdkVersion, maxSdkVersion, result);
    return result;
}
Also used : SignatureInfo(com.android.apksig.internal.apk.SignatureInfo) ApkSigResult(com.android.apksig.internal.apk.ApkSigResult)

Example 3 with SignatureInfo

use of com.android.apksig.internal.apk.SignatureInfo in project apksig by venshine.

the class ApkSignerTest method getRSAPublicKeyFromSigningBlock.

private RSAPublicKey getRSAPublicKeyFromSigningBlock(File apk, int signatureVersionId) throws Exception {
    int signatureVersionBlockId;
    switch(signatureVersionId) {
        case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V2:
            signatureVersionBlockId = V2SchemeConstants.APK_SIGNATURE_SCHEME_V2_BLOCK_ID;
            break;
        case ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3:
            signatureVersionBlockId = V3SchemeConstants.APK_SIGNATURE_SCHEME_V3_BLOCK_ID;
            break;
        default:
            throw new Exception("Invalid signature version ID specified: " + signatureVersionId);
    }
    SignatureInfo signatureInfo = getSignatureInfoFromApk(apk, signatureVersionId, signatureVersionBlockId);
    // FORMAT:
    // * length prefixed sequence of length prefixed signers
    // * length-prefixed signed data
    // * V3+ only - minSDK (uint32)
    // * V3+ only - maxSDK (uint32)
    // * length-prefixed sequence of length-prefixed signatures:
    // * length-prefixed bytes: public key (X.509 SubjectPublicKeyInfo, ASN.1 DER encoded)
    ByteBuffer signers = ApkSigningBlockUtils.getLengthPrefixedSlice(signatureInfo.signatureBlock);
    ByteBuffer signer = ApkSigningBlockUtils.getLengthPrefixedSlice(signers);
    // Since all the data is read from the signer block the signedData and signatures are
    // discarded.
    ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
    // For V3+ signature version IDs discard the min / max SDKs as well
    if (signatureVersionId >= ApkSigningBlockUtils.VERSION_APK_SIGNATURE_SCHEME_V3) {
        signer.getInt();
        signer.getInt();
    }
    ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
    ByteBuffer publicKey = ApkSigningBlockUtils.getLengthPrefixedSlice(signer);
    SubjectPublicKeyInfo subjectPublicKeyInfo = Asn1BerParser.parse(publicKey, SubjectPublicKeyInfo.class);
    ByteBuffer subjectPublicKeyBuffer = subjectPublicKeyInfo.subjectPublicKey;
    // The SubjectPublicKey is stored as a bit string in the SubjectPublicKeyInfo with the first
    // byte indicating the number of padding bits in the public key. Read this first byte to
    // allow parsing the rest of the RSAPublicKey as a sequence.
    subjectPublicKeyBuffer.get();
    return Asn1BerParser.parse(subjectPublicKeyBuffer, RSAPublicKey.class);
}
Also used : SignatureInfo(com.android.apksig.internal.apk.SignatureInfo) ByteBuffer(java.nio.ByteBuffer) SubjectPublicKeyInfo(com.android.apksig.internal.x509.SubjectPublicKeyInfo) SignatureException(java.security.SignatureException) ZipFormatException(com.android.apksig.zip.ZipFormatException) NoSuchAlgorithmException(java.security.NoSuchAlgorithmException) ApkFormatException(com.android.apksig.apk.ApkFormatException) IOException(java.io.IOException)

Example 4 with SignatureInfo

use of com.android.apksig.internal.apk.SignatureInfo in project apksig by venshine.

the class ApkSignerTest method assertSourceStampVerified.

private static void assertSourceStampVerified(File signedApk, ApkVerifier.Result result) throws ApkSigningBlockUtils.SignatureNotFoundException, IOException, ZipFormatException {
    SignatureInfo signatureInfo = getSignatureInfoFromApk(signedApk, ApkSigningBlockUtils.VERSION_SOURCE_STAMP, SourceStampConstants.V2_SOURCE_STAMP_BLOCK_ID);
    assertNotNull(signatureInfo.signatureBlock);
    assertTrue(result.isSourceStampVerified());
}
Also used : SignatureInfo(com.android.apksig.internal.apk.SignatureInfo)

Example 5 with SignatureInfo

use of com.android.apksig.internal.apk.SignatureInfo 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

SignatureInfo (com.android.apksig.internal.apk.SignatureInfo)11 ApkSigningBlockUtils (com.android.apksig.internal.apk.ApkSigningBlockUtils)7 ByteBuffer (java.nio.ByteBuffer)6 ZipFormatException (com.android.apksig.zip.ZipFormatException)5 ContentDigestAlgorithm (com.android.apksig.internal.apk.ContentDigestAlgorithm)4 IOException (java.io.IOException)4 NoSuchAlgorithmException (java.security.NoSuchAlgorithmException)4 ApkFormatException (com.android.apksig.apk.ApkFormatException)3 ApkSigResult (com.android.apksig.internal.apk.ApkSigResult)3 SignatureException (java.security.SignatureException)3 HashSet (java.util.HashSet)3 DataSource (com.android.apksig.util.DataSource)2 InvalidKeyException (java.security.InvalidKeyException)2 CertificateEncodingException (java.security.cert.CertificateEncodingException)2 EnumMap (java.util.EnumMap)2 ApkUtils (com.android.apksig.apk.ApkUtils)1 ApkSignerInfo (com.android.apksig.internal.apk.ApkSignerInfo)1 SignatureAlgorithm (com.android.apksig.internal.apk.SignatureAlgorithm)1 SignatureNotFoundException (com.android.apksig.internal.apk.SignatureNotFoundException)1 V3SigningCertificateLineage (com.android.apksig.internal.apk.v3.V3SigningCertificateLineage)1