Loading core/java/android/os/incremental/IncrementalStorage.java +3 −3 Original line number Diff line number Diff line Loading @@ -505,8 +505,8 @@ public final class IncrementalStorage { final V4Signature.HashingInfo hashingInfo = V4Signature.HashingInfo.fromByteArray( signature.hashingInfo); final V4Signature.SigningInfo signingInfo = V4Signature.SigningInfo.fromByteArray( signature.signingInfo); final V4Signature.SigningInfos signingInfos = V4Signature.SigningInfos.fromByteArray( signature.signingInfos); if (hashingInfo.hashAlgorithm != V4Signature.HASHING_ALGORITHM_SHA256) { throw new IOException("Unsupported hashAlgorithm: " + hashingInfo.hashAlgorithm); Loading @@ -520,7 +520,7 @@ public final class IncrementalStorage { if (hashingInfo.rawRootHash.length != INCFS_MAX_HASH_SIZE) { throw new IOException("rawRootHash has to be " + INCFS_MAX_HASH_SIZE + " bytes"); } if (signingInfo.additionalData.length > INCFS_MAX_ADD_DATA_SIZE) { if (signingInfos.signingInfo.additionalData.length > INCFS_MAX_ADD_DATA_SIZE) { throw new IOException( "additionalData has to be at most " + INCFS_MAX_ADD_DATA_SIZE + " bytes"); } Loading core/java/android/os/incremental/V4Signature.java +71 −8 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; /** * V4 signature fields. Loading Loading @@ -74,7 +75,7 @@ public class V4Signature { } /** * V4 signature data. * Signature data. */ public static class SigningInfo { public final byte[] apkDigest; // used to match with the corresponding APK Loading @@ -98,7 +99,13 @@ public class V4Signature { * Constructs SigningInfo from byte array. */ public static SigningInfo fromByteArray(byte[] bytes) throws IOException { ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); return fromByteBuffer(ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN)); } /** * Constructs SigningInfo from byte buffer. */ public static SigningInfo fromByteBuffer(ByteBuffer buffer) throws IOException { byte[] apkDigest = readBytes(buffer); byte[] certificate = readBytes(buffer); byte[] additionalData = readBytes(buffer); Loading @@ -110,6 +117,62 @@ public class V4Signature { } } /** * Optional signature data block with ID. */ public static class SigningInfoBlock { public final int blockId; public final byte[] signingInfo; public SigningInfoBlock(int blockId, byte[] signingInfo) { this.blockId = blockId; this.signingInfo = signingInfo; } static SigningInfoBlock fromByteBuffer(ByteBuffer buffer) throws IOException { int blockId = buffer.getInt(); byte[] signingInfo = readBytes(buffer); return new SigningInfoBlock(blockId, signingInfo); } } /** * V4 signature data. */ public static class SigningInfos { // Default signature. public final SigningInfo signingInfo; // Additional signatures corresponding to extended V2/V3/V31 blocks. public final SigningInfoBlock[] signingInfoBlocks; public SigningInfos(SigningInfo signingInfo) { this.signingInfo = signingInfo; this.signingInfoBlocks = new SigningInfoBlock[0]; } public SigningInfos(SigningInfo signingInfo, SigningInfoBlock... signingInfoBlocks) { this.signingInfo = signingInfo; this.signingInfoBlocks = signingInfoBlocks; } /** * Constructs SigningInfos from byte array. */ public static SigningInfos fromByteArray(byte[] bytes) throws IOException { ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); SigningInfo signingInfo = SigningInfo.fromByteBuffer(buffer); if (!buffer.hasRemaining()) { return new SigningInfos(signingInfo); } ArrayList<SigningInfoBlock> signingInfoBlocks = new ArrayList<>(1); while (buffer.hasRemaining()) { signingInfoBlocks.add(SigningInfoBlock.fromByteBuffer(buffer)); } return new SigningInfos(signingInfo, signingInfoBlocks.toArray(new SigningInfoBlock[signingInfoBlocks.size()])); } } public final int version; // Always 2 for now. /** * Raw byte array containing the IncFS hashing data. Loading @@ -118,11 +181,11 @@ public class V4Signature { @Nullable public final byte[] hashingInfo; /** * Raw byte array containing the V4 signature data. * Raw byte array containing V4 signatures. * <p>Passed as-is to the kernel. Can be retrieved later. * @see SigningInfo#fromByteArray(byte[]) * @see SigningInfos#fromByteArray(byte[]) */ @Nullable public final byte[] signingInfo; @Nullable public final byte[] signingInfos; /** * Construct a V4Signature from .idsig file. Loading Loading @@ -185,10 +248,10 @@ public class V4Signature { return this.version == SUPPORTED_VERSION; } private V4Signature(int version, @Nullable byte[] hashingInfo, @Nullable byte[] signingInfo) { private V4Signature(int version, @Nullable byte[] hashingInfo, @Nullable byte[] signingInfos) { this.version = version; this.hashingInfo = hashingInfo; this.signingInfo = signingInfo; this.signingInfos = signingInfos; } private static V4Signature readFrom(InputStream stream) throws IOException { Loading @@ -205,7 +268,7 @@ public class V4Signature { private void writeTo(OutputStream stream) throws IOException { writeIntLE(stream, this.version); writeBytes(stream, this.hashingInfo); writeBytes(stream, this.signingInfo); writeBytes(stream, this.signingInfos); } // Utility methods. Loading core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java +10 −4 Original line number Diff line number Diff line Loading @@ -70,8 +70,8 @@ public class ApkSignatureSchemeV3Verifier { */ public static final int SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID = 3; private static final int APK_SIGNATURE_SCHEME_V3_BLOCK_ID = 0xf05368c0; private static final int APK_SIGNATURE_SCHEME_V31_BLOCK_ID = 0x1b93ad61; static final int APK_SIGNATURE_SCHEME_V3_BLOCK_ID = 0xf05368c0; static final int APK_SIGNATURE_SCHEME_V31_BLOCK_ID = 0x1b93ad61; /** * Returns {@code true} if the provided APK contains an APK Signature Scheme V3 signature. Loading Loading @@ -260,7 +260,8 @@ public class ApkSignatureSchemeV3Verifier { verityDigest, mApk.getChannel().size(), signatureInfo); } return new VerifiedSigner(result.first, result.second, verityRootHash, contentDigests); return new VerifiedSigner(result.first, result.second, verityRootHash, contentDigests, blockId); } private Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation> Loading Loading @@ -572,13 +573,18 @@ public class ApkSignatureSchemeV3Verifier { // All these are verified if requested. public final Map<Integer, byte[]> contentDigests; // ID of the signature block used to verify. public final int blockId; public VerifiedSigner(X509Certificate[] certs, ApkSigningBlockUtils.VerifiedProofOfRotation por, byte[] verityRootHash, Map<Integer, byte[]> contentDigests) { byte[] verityRootHash, Map<Integer, byte[]> contentDigests, int blockId) { this.certs = certs; this.por = por; this.verityRootHash = verityRootHash; this.contentDigests = contentDigests; this.blockId = blockId; } } Loading core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java +54 −9 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.util.apk; import static android.util.apk.ApkSignatureSchemeV3Verifier.APK_SIGNATURE_SCHEME_V3_BLOCK_ID; import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256; import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyAlgorithm; import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm; Loading Loading @@ -52,38 +53,60 @@ import java.util.Map; * @hide for internal use only. */ public class ApkSignatureSchemeV4Verifier { static final int APK_SIGNATURE_SCHEME_DEFAULT = 0xffffffff; /** * Extracts and verifies APK Signature Scheme v4 signatures of the provided APK and returns the * Extracts and verifies APK Signature Scheme v4 signature of the provided APK and returns the * certificates associated with each signer. */ public static VerifiedSigner extractCertificates(String apkFile) throws SignatureNotFoundException, SecurityException { V4Signature signature = extractSignature(apkFile); return verify(apkFile, signature, APK_SIGNATURE_SCHEME_DEFAULT); } /** * Extracts APK Signature Scheme v4 signature of the provided APK. */ public static V4Signature extractSignature(String apkFile) throws SignatureNotFoundException { final File apk = new File(apkFile); final byte[] signatureBytes = IncrementalManager.unsafeGetFileSignature( apk.getAbsolutePath()); if (signatureBytes == null || signatureBytes.length == 0) { throw new SignatureNotFoundException("Failed to obtain signature bytes from IncFS."); } final V4Signature signature; final V4Signature.HashingInfo hashingInfo; final V4Signature.SigningInfo signingInfo; try { signature = V4Signature.readFrom(signatureBytes); final V4Signature signature = V4Signature.readFrom(signatureBytes); if (!signature.isVersionSupported()) { throw new SecurityException( "v4 signature version " + signature.version + " is not supported"); } return signature; } catch (IOException e) { throw new SignatureNotFoundException("Failed to read V4 signature.", e); } } /** * Verifies APK Signature Scheme v4 signature and returns the * certificates associated with each signer. */ public static VerifiedSigner verify(String apkFile, final V4Signature signature, final int v3BlockId) throws SignatureNotFoundException, SecurityException { final V4Signature.HashingInfo hashingInfo; final V4Signature.SigningInfos signingInfos; try { hashingInfo = V4Signature.HashingInfo.fromByteArray(signature.hashingInfo); signingInfo = V4Signature.SigningInfo.fromByteArray(signature.signingInfo); signingInfos = V4Signature.SigningInfos.fromByteArray(signature.signingInfos); } catch (IOException e) { throw new SignatureNotFoundException("Failed to read V4 signature.", e); } final V4Signature.SigningInfo signingInfo = findSigningInfoForBlockId(signingInfos, v3BlockId); // Verify signed data and extract certificates and apk digest. final byte[] signedData = V4Signature.getSignedData(apk.length(), hashingInfo, final byte[] signedData = V4Signature.getSignedData(new File(apkFile).length(), hashingInfo, signingInfo); final Pair<Certificate, byte[]> result = verifySigner(signingInfo, signedData); Loading @@ -95,6 +118,28 @@ public class ApkSignatureSchemeV4Verifier { return new VerifiedSigner(new Certificate[]{result.first}, result.second, contentDigests); } private static V4Signature.SigningInfo findSigningInfoForBlockId( final V4Signature.SigningInfos signingInfos, final int v3BlockId) throws SignatureNotFoundException { // Use default signingInfo for v3 block. if (v3BlockId == APK_SIGNATURE_SCHEME_DEFAULT || v3BlockId == APK_SIGNATURE_SCHEME_V3_BLOCK_ID) { return signingInfos.signingInfo; } for (V4Signature.SigningInfoBlock signingInfoBlock : signingInfos.signingInfoBlocks) { if (v3BlockId == signingInfoBlock.blockId) { try { return V4Signature.SigningInfo.fromByteArray(signingInfoBlock.signingInfo); } catch (IOException e) { throw new SecurityException( "Failed to read V4 signature block: " + signingInfoBlock.blockId, e); } } } throw new SecurityException( "Failed to find V4 signature block corresponding to V3 blockId: " + v3BlockId); } private static Pair<Certificate, byte[]> verifySigner(V4Signature.SigningInfo signingInfo, final byte[] signedData) throws SecurityException { if (!isSupportedSignatureAlgorithm(signingInfo.signatureAlgorithmId)) { Loading core/java/android/util/apk/ApkSignatureVerifier.java +42 −34 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTEN import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.util.apk.ApkSignatureSchemeV4Verifier.APK_SIGNATURE_SCHEME_DEFAULT; import android.content.pm.Signature; import android.content.pm.SigningDetails; Loading @@ -31,6 +32,7 @@ import android.content.pm.parsing.result.ParseInput; import android.content.pm.parsing.result.ParseResult; import android.os.Build; import android.os.Trace; import android.os.incremental.V4Signature; import android.util.jar.StrictJarFile; import com.android.internal.util.ArrayUtils; Loading Loading @@ -189,16 +191,15 @@ public class ApkSignatureVerifier { boolean verifyFull) throws SignatureNotFoundException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV4" : "certsOnlyV4"); try { ApkSignatureSchemeV4Verifier.VerifiedSigner vSigner = ApkSignatureSchemeV4Verifier.extractCertificates(apkPath); Certificate[][] signerCerts = new Certificate[][]{vSigner.certs}; Signature[] signerSigs = convertToSignatures(signerCerts); final V4Signature v4Signature = ApkSignatureSchemeV4Verifier.extractSignature(apkPath); Signature[] pastSignerSigs = null; if (verifyFull) { Map<Integer, byte[]> nonstreamingDigests; Certificate[][] nonstreamingCerts; int v3BlockId = APK_SIGNATURE_SCHEME_DEFAULT; try { // v4 is an add-on and requires v2 or v3 signature to validate against its // certificate and digest Loading @@ -215,6 +216,7 @@ public class ApkSignatureVerifier { pastSignerSigs[i].setFlags(v3Signer.por.flagsList.get(i)); } } v3BlockId = v3Signer.blockId; } catch (SignatureNotFoundException e) { try { ApkSignatureSchemeV2Verifier.VerifiedSigner v2Signer = Loading @@ -228,6 +230,12 @@ public class ApkSignatureVerifier { } } ApkSignatureSchemeV4Verifier.VerifiedSigner vSigner = ApkSignatureSchemeV4Verifier.verify(apkPath, v4Signature, v3BlockId); Certificate[][] signerCerts = new Certificate[][]{vSigner.certs}; Signature[] signerSigs = convertToSignatures(signerCerts); if (verifyFull) { Signature[] nonstreamingSigs = convertToSignatures(nonstreamingCerts); if (nonstreamingSigs.length != signerSigs.length) { throw new SecurityException( Loading Loading @@ -260,7 +268,7 @@ public class ApkSignatureVerifier { } catch (SignatureNotFoundException e) { throw e; } catch (Exception e) { // APK Signature Scheme v4 signature found but did not verify // APK Signature Scheme v4 signature found but did not verify. return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Failed to collect certificates from " + apkPath + " using APK Signature Scheme v4", e); Loading Loading
core/java/android/os/incremental/IncrementalStorage.java +3 −3 Original line number Diff line number Diff line Loading @@ -505,8 +505,8 @@ public final class IncrementalStorage { final V4Signature.HashingInfo hashingInfo = V4Signature.HashingInfo.fromByteArray( signature.hashingInfo); final V4Signature.SigningInfo signingInfo = V4Signature.SigningInfo.fromByteArray( signature.signingInfo); final V4Signature.SigningInfos signingInfos = V4Signature.SigningInfos.fromByteArray( signature.signingInfos); if (hashingInfo.hashAlgorithm != V4Signature.HASHING_ALGORITHM_SHA256) { throw new IOException("Unsupported hashAlgorithm: " + hashingInfo.hashAlgorithm); Loading @@ -520,7 +520,7 @@ public final class IncrementalStorage { if (hashingInfo.rawRootHash.length != INCFS_MAX_HASH_SIZE) { throw new IOException("rawRootHash has to be " + INCFS_MAX_HASH_SIZE + " bytes"); } if (signingInfo.additionalData.length > INCFS_MAX_ADD_DATA_SIZE) { if (signingInfos.signingInfo.additionalData.length > INCFS_MAX_ADD_DATA_SIZE) { throw new IOException( "additionalData has to be at most " + INCFS_MAX_ADD_DATA_SIZE + " bytes"); } Loading
core/java/android/os/incremental/V4Signature.java +71 −8 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.util.ArrayList; /** * V4 signature fields. Loading Loading @@ -74,7 +75,7 @@ public class V4Signature { } /** * V4 signature data. * Signature data. */ public static class SigningInfo { public final byte[] apkDigest; // used to match with the corresponding APK Loading @@ -98,7 +99,13 @@ public class V4Signature { * Constructs SigningInfo from byte array. */ public static SigningInfo fromByteArray(byte[] bytes) throws IOException { ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); return fromByteBuffer(ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN)); } /** * Constructs SigningInfo from byte buffer. */ public static SigningInfo fromByteBuffer(ByteBuffer buffer) throws IOException { byte[] apkDigest = readBytes(buffer); byte[] certificate = readBytes(buffer); byte[] additionalData = readBytes(buffer); Loading @@ -110,6 +117,62 @@ public class V4Signature { } } /** * Optional signature data block with ID. */ public static class SigningInfoBlock { public final int blockId; public final byte[] signingInfo; public SigningInfoBlock(int blockId, byte[] signingInfo) { this.blockId = blockId; this.signingInfo = signingInfo; } static SigningInfoBlock fromByteBuffer(ByteBuffer buffer) throws IOException { int blockId = buffer.getInt(); byte[] signingInfo = readBytes(buffer); return new SigningInfoBlock(blockId, signingInfo); } } /** * V4 signature data. */ public static class SigningInfos { // Default signature. public final SigningInfo signingInfo; // Additional signatures corresponding to extended V2/V3/V31 blocks. public final SigningInfoBlock[] signingInfoBlocks; public SigningInfos(SigningInfo signingInfo) { this.signingInfo = signingInfo; this.signingInfoBlocks = new SigningInfoBlock[0]; } public SigningInfos(SigningInfo signingInfo, SigningInfoBlock... signingInfoBlocks) { this.signingInfo = signingInfo; this.signingInfoBlocks = signingInfoBlocks; } /** * Constructs SigningInfos from byte array. */ public static SigningInfos fromByteArray(byte[] bytes) throws IOException { ByteBuffer buffer = ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN); SigningInfo signingInfo = SigningInfo.fromByteBuffer(buffer); if (!buffer.hasRemaining()) { return new SigningInfos(signingInfo); } ArrayList<SigningInfoBlock> signingInfoBlocks = new ArrayList<>(1); while (buffer.hasRemaining()) { signingInfoBlocks.add(SigningInfoBlock.fromByteBuffer(buffer)); } return new SigningInfos(signingInfo, signingInfoBlocks.toArray(new SigningInfoBlock[signingInfoBlocks.size()])); } } public final int version; // Always 2 for now. /** * Raw byte array containing the IncFS hashing data. Loading @@ -118,11 +181,11 @@ public class V4Signature { @Nullable public final byte[] hashingInfo; /** * Raw byte array containing the V4 signature data. * Raw byte array containing V4 signatures. * <p>Passed as-is to the kernel. Can be retrieved later. * @see SigningInfo#fromByteArray(byte[]) * @see SigningInfos#fromByteArray(byte[]) */ @Nullable public final byte[] signingInfo; @Nullable public final byte[] signingInfos; /** * Construct a V4Signature from .idsig file. Loading Loading @@ -185,10 +248,10 @@ public class V4Signature { return this.version == SUPPORTED_VERSION; } private V4Signature(int version, @Nullable byte[] hashingInfo, @Nullable byte[] signingInfo) { private V4Signature(int version, @Nullable byte[] hashingInfo, @Nullable byte[] signingInfos) { this.version = version; this.hashingInfo = hashingInfo; this.signingInfo = signingInfo; this.signingInfos = signingInfos; } private static V4Signature readFrom(InputStream stream) throws IOException { Loading @@ -205,7 +268,7 @@ public class V4Signature { private void writeTo(OutputStream stream) throws IOException { writeIntLE(stream, this.version); writeBytes(stream, this.hashingInfo); writeBytes(stream, this.signingInfo); writeBytes(stream, this.signingInfos); } // Utility methods. Loading
core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java +10 −4 Original line number Diff line number Diff line Loading @@ -70,8 +70,8 @@ public class ApkSignatureSchemeV3Verifier { */ public static final int SF_ATTRIBUTE_ANDROID_APK_SIGNED_ID = 3; private static final int APK_SIGNATURE_SCHEME_V3_BLOCK_ID = 0xf05368c0; private static final int APK_SIGNATURE_SCHEME_V31_BLOCK_ID = 0x1b93ad61; static final int APK_SIGNATURE_SCHEME_V3_BLOCK_ID = 0xf05368c0; static final int APK_SIGNATURE_SCHEME_V31_BLOCK_ID = 0x1b93ad61; /** * Returns {@code true} if the provided APK contains an APK Signature Scheme V3 signature. Loading Loading @@ -260,7 +260,8 @@ public class ApkSignatureSchemeV3Verifier { verityDigest, mApk.getChannel().size(), signatureInfo); } return new VerifiedSigner(result.first, result.second, verityRootHash, contentDigests); return new VerifiedSigner(result.first, result.second, verityRootHash, contentDigests, blockId); } private Pair<X509Certificate[], ApkSigningBlockUtils.VerifiedProofOfRotation> Loading Loading @@ -572,13 +573,18 @@ public class ApkSignatureSchemeV3Verifier { // All these are verified if requested. public final Map<Integer, byte[]> contentDigests; // ID of the signature block used to verify. public final int blockId; public VerifiedSigner(X509Certificate[] certs, ApkSigningBlockUtils.VerifiedProofOfRotation por, byte[] verityRootHash, Map<Integer, byte[]> contentDigests) { byte[] verityRootHash, Map<Integer, byte[]> contentDigests, int blockId) { this.certs = certs; this.por = por; this.verityRootHash = verityRootHash; this.contentDigests = contentDigests; this.blockId = blockId; } } Loading
core/java/android/util/apk/ApkSignatureSchemeV4Verifier.java +54 −9 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.util.apk; import static android.util.apk.ApkSignatureSchemeV3Verifier.APK_SIGNATURE_SCHEME_V3_BLOCK_ID; import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256; import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaKeyAlgorithm; import static android.util.apk.ApkSigningBlockUtils.getSignatureAlgorithmJcaSignatureAlgorithm; Loading Loading @@ -52,38 +53,60 @@ import java.util.Map; * @hide for internal use only. */ public class ApkSignatureSchemeV4Verifier { static final int APK_SIGNATURE_SCHEME_DEFAULT = 0xffffffff; /** * Extracts and verifies APK Signature Scheme v4 signatures of the provided APK and returns the * Extracts and verifies APK Signature Scheme v4 signature of the provided APK and returns the * certificates associated with each signer. */ public static VerifiedSigner extractCertificates(String apkFile) throws SignatureNotFoundException, SecurityException { V4Signature signature = extractSignature(apkFile); return verify(apkFile, signature, APK_SIGNATURE_SCHEME_DEFAULT); } /** * Extracts APK Signature Scheme v4 signature of the provided APK. */ public static V4Signature extractSignature(String apkFile) throws SignatureNotFoundException { final File apk = new File(apkFile); final byte[] signatureBytes = IncrementalManager.unsafeGetFileSignature( apk.getAbsolutePath()); if (signatureBytes == null || signatureBytes.length == 0) { throw new SignatureNotFoundException("Failed to obtain signature bytes from IncFS."); } final V4Signature signature; final V4Signature.HashingInfo hashingInfo; final V4Signature.SigningInfo signingInfo; try { signature = V4Signature.readFrom(signatureBytes); final V4Signature signature = V4Signature.readFrom(signatureBytes); if (!signature.isVersionSupported()) { throw new SecurityException( "v4 signature version " + signature.version + " is not supported"); } return signature; } catch (IOException e) { throw new SignatureNotFoundException("Failed to read V4 signature.", e); } } /** * Verifies APK Signature Scheme v4 signature and returns the * certificates associated with each signer. */ public static VerifiedSigner verify(String apkFile, final V4Signature signature, final int v3BlockId) throws SignatureNotFoundException, SecurityException { final V4Signature.HashingInfo hashingInfo; final V4Signature.SigningInfos signingInfos; try { hashingInfo = V4Signature.HashingInfo.fromByteArray(signature.hashingInfo); signingInfo = V4Signature.SigningInfo.fromByteArray(signature.signingInfo); signingInfos = V4Signature.SigningInfos.fromByteArray(signature.signingInfos); } catch (IOException e) { throw new SignatureNotFoundException("Failed to read V4 signature.", e); } final V4Signature.SigningInfo signingInfo = findSigningInfoForBlockId(signingInfos, v3BlockId); // Verify signed data and extract certificates and apk digest. final byte[] signedData = V4Signature.getSignedData(apk.length(), hashingInfo, final byte[] signedData = V4Signature.getSignedData(new File(apkFile).length(), hashingInfo, signingInfo); final Pair<Certificate, byte[]> result = verifySigner(signingInfo, signedData); Loading @@ -95,6 +118,28 @@ public class ApkSignatureSchemeV4Verifier { return new VerifiedSigner(new Certificate[]{result.first}, result.second, contentDigests); } private static V4Signature.SigningInfo findSigningInfoForBlockId( final V4Signature.SigningInfos signingInfos, final int v3BlockId) throws SignatureNotFoundException { // Use default signingInfo for v3 block. if (v3BlockId == APK_SIGNATURE_SCHEME_DEFAULT || v3BlockId == APK_SIGNATURE_SCHEME_V3_BLOCK_ID) { return signingInfos.signingInfo; } for (V4Signature.SigningInfoBlock signingInfoBlock : signingInfos.signingInfoBlocks) { if (v3BlockId == signingInfoBlock.blockId) { try { return V4Signature.SigningInfo.fromByteArray(signingInfoBlock.signingInfo); } catch (IOException e) { throw new SecurityException( "Failed to read V4 signature block: " + signingInfoBlock.blockId, e); } } } throw new SecurityException( "Failed to find V4 signature block corresponding to V3 blockId: " + v3BlockId); } private static Pair<Certificate, byte[]> verifySigner(V4Signature.SigningInfo signingInfo, final byte[] signedData) throws SecurityException { if (!isSupportedSignatureAlgorithm(signingInfo.signatureAlgorithmId)) { Loading
core/java/android/util/apk/ApkSignatureVerifier.java +42 −34 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTEN import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NO_CERTIFICATES; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.util.apk.ApkSignatureSchemeV4Verifier.APK_SIGNATURE_SCHEME_DEFAULT; import android.content.pm.Signature; import android.content.pm.SigningDetails; Loading @@ -31,6 +32,7 @@ import android.content.pm.parsing.result.ParseInput; import android.content.pm.parsing.result.ParseResult; import android.os.Build; import android.os.Trace; import android.os.incremental.V4Signature; import android.util.jar.StrictJarFile; import com.android.internal.util.ArrayUtils; Loading Loading @@ -189,16 +191,15 @@ public class ApkSignatureVerifier { boolean verifyFull) throws SignatureNotFoundException { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, verifyFull ? "verifyV4" : "certsOnlyV4"); try { ApkSignatureSchemeV4Verifier.VerifiedSigner vSigner = ApkSignatureSchemeV4Verifier.extractCertificates(apkPath); Certificate[][] signerCerts = new Certificate[][]{vSigner.certs}; Signature[] signerSigs = convertToSignatures(signerCerts); final V4Signature v4Signature = ApkSignatureSchemeV4Verifier.extractSignature(apkPath); Signature[] pastSignerSigs = null; if (verifyFull) { Map<Integer, byte[]> nonstreamingDigests; Certificate[][] nonstreamingCerts; int v3BlockId = APK_SIGNATURE_SCHEME_DEFAULT; try { // v4 is an add-on and requires v2 or v3 signature to validate against its // certificate and digest Loading @@ -215,6 +216,7 @@ public class ApkSignatureVerifier { pastSignerSigs[i].setFlags(v3Signer.por.flagsList.get(i)); } } v3BlockId = v3Signer.blockId; } catch (SignatureNotFoundException e) { try { ApkSignatureSchemeV2Verifier.VerifiedSigner v2Signer = Loading @@ -228,6 +230,12 @@ public class ApkSignatureVerifier { } } ApkSignatureSchemeV4Verifier.VerifiedSigner vSigner = ApkSignatureSchemeV4Verifier.verify(apkPath, v4Signature, v3BlockId); Certificate[][] signerCerts = new Certificate[][]{vSigner.certs}; Signature[] signerSigs = convertToSignatures(signerCerts); if (verifyFull) { Signature[] nonstreamingSigs = convertToSignatures(nonstreamingCerts); if (nonstreamingSigs.length != signerSigs.length) { throw new SecurityException( Loading Loading @@ -260,7 +268,7 @@ public class ApkSignatureVerifier { } catch (SignatureNotFoundException e) { throw e; } catch (Exception e) { // APK Signature Scheme v4 signature found but did not verify // APK Signature Scheme v4 signature found but did not verify. return input.error(INSTALL_PARSE_FAILED_NO_CERTIFICATES, "Failed to collect certificates from " + apkPath + " using APK Signature Scheme v4", e); Loading