Loading core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java +51 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.util.apk; import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_DSA_WITH_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA512; Loading @@ -42,6 +43,7 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.security.DigestException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyFactory; Loading Loading @@ -105,7 +107,8 @@ public class ApkSignatureSchemeV2Verifier { */ public static X509Certificate[][] verify(String apkFile) throws SignatureNotFoundException, SecurityException, IOException { return verify(apkFile, true); VerifiedSigner vSigner = verify(apkFile, true); return vSigner.certs; } /** Loading @@ -119,10 +122,11 @@ public class ApkSignatureSchemeV2Verifier { */ public static X509Certificate[][] plsCertsNoVerifyOnlyCerts(String apkFile) throws SignatureNotFoundException, SecurityException, IOException { return verify(apkFile, false); VerifiedSigner vSigner = verify(apkFile, false); return vSigner.certs; } private static X509Certificate[][] verify(String apkFile, boolean verifyIntegrity) private static VerifiedSigner verify(String apkFile, boolean verifyIntegrity) throws SignatureNotFoundException, SecurityException, IOException { try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) { return verify(apk, verifyIntegrity); Loading @@ -138,7 +142,7 @@ public class ApkSignatureSchemeV2Verifier { * verify. * @throws IOException if an I/O error occurs while reading the APK file. */ private static X509Certificate[][] verify(RandomAccessFile apk, boolean verifyIntegrity) private static VerifiedSigner verify(RandomAccessFile apk, boolean verifyIntegrity) throws SignatureNotFoundException, SecurityException, IOException { SignatureInfo signatureInfo = findSignature(apk); return verify(apk, signatureInfo, verifyIntegrity); Loading @@ -163,7 +167,7 @@ public class ApkSignatureSchemeV2Verifier { * @param signatureInfo APK Signature Scheme v2 Block and information relevant for verifying it * against the APK file. */ private static X509Certificate[][] verify( private static VerifiedSigner verify( RandomAccessFile apk, SignatureInfo signatureInfo, boolean doVerifyIntegrity) throws SecurityException, IOException { Loading Loading @@ -207,7 +211,14 @@ public class ApkSignatureSchemeV2Verifier { ApkSigningBlockUtils.verifyIntegrity(contentDigests, apk, signatureInfo); } return signerCerts.toArray(new X509Certificate[signerCerts.size()][]); byte[] verityRootHash = null; if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) { verityRootHash = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256); } return new VerifiedSigner( signerCerts.toArray(new X509Certificate[signerCerts.size()][]), verityRootHash); } private static X509Certificate[] verifySigner( Loading Loading @@ -383,6 +394,24 @@ public class ApkSignatureSchemeV2Verifier { return; } static byte[] getVerityRootHash(String apkPath) throws IOException, SignatureNotFoundException, SecurityException { try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { SignatureInfo signatureInfo = findSignature(apk); VerifiedSigner vSigner = verify(apk, false); return vSigner.verityRootHash; } } static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory) throws IOException, SignatureNotFoundException, SecurityException, DigestException, NoSuchAlgorithmException { try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { SignatureInfo signatureInfo = findSignature(apk); return ApkSigningBlockUtils.generateApkVerity(apkPath, bufferFactory, signatureInfo); } } private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) { switch (sigAlgorithm) { case SIGNATURE_RSA_PSS_WITH_SHA256: Loading @@ -400,4 +429,20 @@ public class ApkSignatureSchemeV2Verifier { return false; } } /** * Verified APK Signature Scheme v2 signer. * * @hide for internal use only. */ public static class VerifiedSigner { public final X509Certificate[][] certs; public final byte[] verityRootHash; public VerifiedSigner(X509Certificate[][] certs, byte[] verityRootHash) { this.certs = certs; this.verityRootHash = verityRootHash; } } } core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java +26 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.util.apk; import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_DSA_WITH_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA512; Loading Loading @@ -43,6 +44,7 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.security.DigestException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyFactory; Loading Loading @@ -211,6 +213,10 @@ public class ApkSignatureSchemeV3Verifier { ApkSigningBlockUtils.verifyIntegrity(contentDigests, apk, signatureInfo); } if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) { result.verityRootHash = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256); } return result; } Loading Loading @@ -499,6 +505,24 @@ public class ApkSignatureSchemeV3Verifier { return new VerifiedProofOfRotation(certs, flagsList); } static byte[] getVerityRootHash(String apkPath) throws IOException, SignatureNotFoundException, SecurityException { try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { SignatureInfo signatureInfo = findSignature(apk); VerifiedSigner vSigner = verify(apk, false); return vSigner.verityRootHash; } } static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory) throws IOException, SignatureNotFoundException, SecurityException, DigestException, NoSuchAlgorithmException { try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { SignatureInfo signatureInfo = findSignature(apk); return ApkSigningBlockUtils.generateApkVerity(apkPath, bufferFactory, signatureInfo); } } private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) { switch (sigAlgorithm) { case SIGNATURE_RSA_PSS_WITH_SHA256: Loading Loading @@ -541,6 +565,8 @@ public class ApkSignatureSchemeV3Verifier { public final X509Certificate[] certs; public final VerifiedProofOfRotation por; public byte[] verityRootHash; public VerifiedSigner(X509Certificate[] certs, VerifiedProofOfRotation por) { this.certs = certs; this.por = por; Loading core/java/android/util/apk/ApkSignatureVerifier.java +49 −0 Original line number Diff line number Diff line Loading @@ -36,7 +36,9 @@ import libcore.io.IoUtils; import java.io.IOException; import java.io.InputStream; import java.security.DigestException; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.util.ArrayList; Loading Loading @@ -367,4 +369,51 @@ public class ApkSignatureVerifier { // v2 didn't work, try jarsigner return verifyV1Signature(apkPath, false); } /** * @return the verity root hash in the Signing Block. */ public static byte[] getVerityRootHash(String apkPath) throws IOException, SignatureNotFoundException, SecurityException { // first try v3 try { return ApkSignatureSchemeV3Verifier.getVerityRootHash(apkPath); } catch (SignatureNotFoundException e) { // try older version } return ApkSignatureSchemeV2Verifier.getVerityRootHash(apkPath); } /** * Generates the Merkle tree and verity metadata to the buffer allocated by the {@code * ByteBufferFactory}. * * @return the verity root hash of the generated Merkle tree. */ public static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory) throws IOException, SignatureNotFoundException, SecurityException, DigestException, NoSuchAlgorithmException { // first try v3 try { return ApkSignatureSchemeV3Verifier.generateApkVerity(apkPath, bufferFactory); } catch (SignatureNotFoundException e) { // try older version } return ApkSignatureSchemeV2Verifier.generateApkVerity(apkPath, bufferFactory); } /** * Result of a successful APK verification operation. */ public static class Result { public final Certificate[][] certs; public final Signature[] sigs; public final int signatureSchemeVersion; public Result(Certificate[][] certs, Signature[] sigs, int signingVersion) { this.certs = certs; this.sigs = sigs; this.signatureSchemeVersion = signingVersion; } } } core/java/android/util/apk/ApkSigningBlockUtils.java +20 −0 Original line number Diff line number Diff line Loading @@ -305,6 +305,26 @@ final class ApkSigningBlockUtils { } } /** * Generates the fsverity header and hash tree to be used by kernel for the given apk. This * method does not check whether the root hash exists in the Signing Block or not. * * <p>The output is stored in the {@link ByteBuffer} created by the given {@link * ByteBufferFactory}. * * @return the root hash of the generated hash tree. */ public static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory, SignatureInfo signatureInfo) throws IOException, SignatureNotFoundException, SecurityException, DigestException, NoSuchAlgorithmException { try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { ApkVerityBuilder.ApkVerityResult result = ApkVerityBuilder.generateApkVerity(apk, signatureInfo, bufferFactory); return result.rootHash; } } /** * Returns the ZIP End of Central Directory (EoCD) and its offset in the file. * Loading Loading
core/java/android/util/apk/ApkSignatureSchemeV2Verifier.java +51 −6 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.util.apk; import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_DSA_WITH_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA512; Loading @@ -42,6 +43,7 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.security.DigestException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyFactory; Loading Loading @@ -105,7 +107,8 @@ public class ApkSignatureSchemeV2Verifier { */ public static X509Certificate[][] verify(String apkFile) throws SignatureNotFoundException, SecurityException, IOException { return verify(apkFile, true); VerifiedSigner vSigner = verify(apkFile, true); return vSigner.certs; } /** Loading @@ -119,10 +122,11 @@ public class ApkSignatureSchemeV2Verifier { */ public static X509Certificate[][] plsCertsNoVerifyOnlyCerts(String apkFile) throws SignatureNotFoundException, SecurityException, IOException { return verify(apkFile, false); VerifiedSigner vSigner = verify(apkFile, false); return vSigner.certs; } private static X509Certificate[][] verify(String apkFile, boolean verifyIntegrity) private static VerifiedSigner verify(String apkFile, boolean verifyIntegrity) throws SignatureNotFoundException, SecurityException, IOException { try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) { return verify(apk, verifyIntegrity); Loading @@ -138,7 +142,7 @@ public class ApkSignatureSchemeV2Verifier { * verify. * @throws IOException if an I/O error occurs while reading the APK file. */ private static X509Certificate[][] verify(RandomAccessFile apk, boolean verifyIntegrity) private static VerifiedSigner verify(RandomAccessFile apk, boolean verifyIntegrity) throws SignatureNotFoundException, SecurityException, IOException { SignatureInfo signatureInfo = findSignature(apk); return verify(apk, signatureInfo, verifyIntegrity); Loading @@ -163,7 +167,7 @@ public class ApkSignatureSchemeV2Verifier { * @param signatureInfo APK Signature Scheme v2 Block and information relevant for verifying it * against the APK file. */ private static X509Certificate[][] verify( private static VerifiedSigner verify( RandomAccessFile apk, SignatureInfo signatureInfo, boolean doVerifyIntegrity) throws SecurityException, IOException { Loading Loading @@ -207,7 +211,14 @@ public class ApkSignatureSchemeV2Verifier { ApkSigningBlockUtils.verifyIntegrity(contentDigests, apk, signatureInfo); } return signerCerts.toArray(new X509Certificate[signerCerts.size()][]); byte[] verityRootHash = null; if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) { verityRootHash = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256); } return new VerifiedSigner( signerCerts.toArray(new X509Certificate[signerCerts.size()][]), verityRootHash); } private static X509Certificate[] verifySigner( Loading Loading @@ -383,6 +394,24 @@ public class ApkSignatureSchemeV2Verifier { return; } static byte[] getVerityRootHash(String apkPath) throws IOException, SignatureNotFoundException, SecurityException { try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { SignatureInfo signatureInfo = findSignature(apk); VerifiedSigner vSigner = verify(apk, false); return vSigner.verityRootHash; } } static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory) throws IOException, SignatureNotFoundException, SecurityException, DigestException, NoSuchAlgorithmException { try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { SignatureInfo signatureInfo = findSignature(apk); return ApkSigningBlockUtils.generateApkVerity(apkPath, bufferFactory, signatureInfo); } } private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) { switch (sigAlgorithm) { case SIGNATURE_RSA_PSS_WITH_SHA256: Loading @@ -400,4 +429,20 @@ public class ApkSignatureSchemeV2Verifier { return false; } } /** * Verified APK Signature Scheme v2 signer. * * @hide for internal use only. */ public static class VerifiedSigner { public final X509Certificate[][] certs; public final byte[] verityRootHash; public VerifiedSigner(X509Certificate[][] certs, byte[] verityRootHash) { this.certs = certs; this.verityRootHash = verityRootHash; } } }
core/java/android/util/apk/ApkSignatureSchemeV3Verifier.java +26 −0 Original line number Diff line number Diff line Loading @@ -16,6 +16,7 @@ package android.util.apk; import static android.util.apk.ApkSigningBlockUtils.CONTENT_DIGEST_VERITY_CHUNKED_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_DSA_WITH_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA256; import static android.util.apk.ApkSigningBlockUtils.SIGNATURE_ECDSA_WITH_SHA512; Loading Loading @@ -43,6 +44,7 @@ import java.io.IOException; import java.io.RandomAccessFile; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.security.DigestException; import java.security.InvalidAlgorithmParameterException; import java.security.InvalidKeyException; import java.security.KeyFactory; Loading Loading @@ -211,6 +213,10 @@ public class ApkSignatureSchemeV3Verifier { ApkSigningBlockUtils.verifyIntegrity(contentDigests, apk, signatureInfo); } if (contentDigests.containsKey(CONTENT_DIGEST_VERITY_CHUNKED_SHA256)) { result.verityRootHash = contentDigests.get(CONTENT_DIGEST_VERITY_CHUNKED_SHA256); } return result; } Loading Loading @@ -499,6 +505,24 @@ public class ApkSignatureSchemeV3Verifier { return new VerifiedProofOfRotation(certs, flagsList); } static byte[] getVerityRootHash(String apkPath) throws IOException, SignatureNotFoundException, SecurityException { try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { SignatureInfo signatureInfo = findSignature(apk); VerifiedSigner vSigner = verify(apk, false); return vSigner.verityRootHash; } } static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory) throws IOException, SignatureNotFoundException, SecurityException, DigestException, NoSuchAlgorithmException { try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { SignatureInfo signatureInfo = findSignature(apk); return ApkSigningBlockUtils.generateApkVerity(apkPath, bufferFactory, signatureInfo); } } private static boolean isSupportedSignatureAlgorithm(int sigAlgorithm) { switch (sigAlgorithm) { case SIGNATURE_RSA_PSS_WITH_SHA256: Loading Loading @@ -541,6 +565,8 @@ public class ApkSignatureSchemeV3Verifier { public final X509Certificate[] certs; public final VerifiedProofOfRotation por; public byte[] verityRootHash; public VerifiedSigner(X509Certificate[] certs, VerifiedProofOfRotation por) { this.certs = certs; this.por = por; Loading
core/java/android/util/apk/ApkSignatureVerifier.java +49 −0 Original line number Diff line number Diff line Loading @@ -36,7 +36,9 @@ import libcore.io.IoUtils; import java.io.IOException; import java.io.InputStream; import java.security.DigestException; import java.security.GeneralSecurityException; import java.security.NoSuchAlgorithmException; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.util.ArrayList; Loading Loading @@ -367,4 +369,51 @@ public class ApkSignatureVerifier { // v2 didn't work, try jarsigner return verifyV1Signature(apkPath, false); } /** * @return the verity root hash in the Signing Block. */ public static byte[] getVerityRootHash(String apkPath) throws IOException, SignatureNotFoundException, SecurityException { // first try v3 try { return ApkSignatureSchemeV3Verifier.getVerityRootHash(apkPath); } catch (SignatureNotFoundException e) { // try older version } return ApkSignatureSchemeV2Verifier.getVerityRootHash(apkPath); } /** * Generates the Merkle tree and verity metadata to the buffer allocated by the {@code * ByteBufferFactory}. * * @return the verity root hash of the generated Merkle tree. */ public static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory) throws IOException, SignatureNotFoundException, SecurityException, DigestException, NoSuchAlgorithmException { // first try v3 try { return ApkSignatureSchemeV3Verifier.generateApkVerity(apkPath, bufferFactory); } catch (SignatureNotFoundException e) { // try older version } return ApkSignatureSchemeV2Verifier.generateApkVerity(apkPath, bufferFactory); } /** * Result of a successful APK verification operation. */ public static class Result { public final Certificate[][] certs; public final Signature[] sigs; public final int signatureSchemeVersion; public Result(Certificate[][] certs, Signature[] sigs, int signingVersion) { this.certs = certs; this.sigs = sigs; this.signatureSchemeVersion = signingVersion; } } }
core/java/android/util/apk/ApkSigningBlockUtils.java +20 −0 Original line number Diff line number Diff line Loading @@ -305,6 +305,26 @@ final class ApkSigningBlockUtils { } } /** * Generates the fsverity header and hash tree to be used by kernel for the given apk. This * method does not check whether the root hash exists in the Signing Block or not. * * <p>The output is stored in the {@link ByteBuffer} created by the given {@link * ByteBufferFactory}. * * @return the root hash of the generated hash tree. */ public static byte[] generateApkVerity(String apkPath, ByteBufferFactory bufferFactory, SignatureInfo signatureInfo) throws IOException, SignatureNotFoundException, SecurityException, DigestException, NoSuchAlgorithmException { try (RandomAccessFile apk = new RandomAccessFile(apkPath, "r")) { ApkVerityBuilder.ApkVerityResult result = ApkVerityBuilder.generateApkVerity(apk, signatureInfo, bufferFactory); return result.rootHash; } } /** * Returns the ZIP End of Central Directory (EoCD) and its offset in the file. * Loading