Loading core/java/android/util/apk/SourceStampVerifier.java +37 −25 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.util.apk.ApkSigningBlockUtils.isSupportedSignatureAlgorith import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray; import android.util.Pair; import android.util.Slog; import android.util.jar.StrictJarFile; import libcore.io.IoUtils; Loading Loading @@ -69,6 +70,8 @@ import java.util.zip.ZipEntry; */ public abstract class SourceStampVerifier { private static final String TAG = "SourceStampVerifier"; private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a; private static final int APK_SIGNATURE_SCHEME_V3_BLOCK_ID = 0xf05368c0; private static final int SOURCE_STAMP_BLOCK_ID = 0x2b09189e; Loading Loading @@ -99,28 +102,31 @@ public abstract class SourceStampVerifier { /** Verifies SourceStamp present in the provided APK. */ public static SourceStampVerificationResult verify(String apkFile) { StrictJarFile apkJar = null; try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) { return verify(apk); } catch (IOException e) { // Any exception in reading the APK returns a non-present SourceStamp outcome // without affecting the outcome of any of the other signature schemes. return SourceStampVerificationResult.notPresent(); } } private static SourceStampVerificationResult verify(RandomAccessFile apk) { byte[] sourceStampCertificateDigest; try { sourceStampCertificateDigest = getSourceStampCertificateDigest(apk); apkJar = new StrictJarFile( apkFile, /* verify= */ false, /* signatureSchemeRollbackProtectionsEnforced= */ false); byte[] sourceStampCertificateDigest = getSourceStampCertificateDigest(apkJar); if (sourceStampCertificateDigest == null) { // SourceStamp certificate hash file not found, which means that there is not // SourceStamp present. return SourceStampVerificationResult.notPresent(); } return verify(apk, sourceStampCertificateDigest); } catch (IOException e) { // Any exception in reading the APK returns a non-present SourceStamp outcome // without affecting the outcome of any of the other signature schemes. return SourceStampVerificationResult.notPresent(); } finally { closeApkJar(apkJar); } } private static SourceStampVerificationResult verify( RandomAccessFile apk, byte[] sourceStampCertificateDigest) { try { SignatureInfo signatureInfo = ApkSigningBlockUtils.findSignature(apk, SOURCE_STAMP_BLOCK_ID); Loading Loading @@ -283,22 +289,17 @@ public abstract class SourceStampVerifier { return apkContentDigests; } private static byte[] getSourceStampCertificateDigest(RandomAccessFile apk) throws IOException { StrictJarFile apkJar = new StrictJarFile( apk.getFD(), /* verify= */ false, /* signatureSchemeRollbackProtectionsEnforced= */ false); private static byte[] getSourceStampCertificateDigest(StrictJarFile apkJar) throws IOException { InputStream inputStream = null; try { ZipEntry zipEntry = apkJar.findEntry(SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME); if (zipEntry == null) { // SourceStamp certificate hash file not found, which means that there is not // SourceStamp present. return null; } InputStream inputStream = null; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try { inputStream = apkJar.getInputStream(zipEntry); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Trying to read the certificate digest, which should be less than 1024 bytes. byte[] buffer = new byte[1024]; Loading Loading @@ -327,4 +328,15 @@ public abstract class SourceStampVerifier { } return result.array(); } private static void closeApkJar(StrictJarFile apkJar) { try { if (apkJar == null) { return; } apkJar.close(); } catch (IOException e) { Slog.e(TAG, "Could not close APK jar", e); } } } services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +4 −2 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateEncodingException; Loading @@ -88,6 +89,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; /** Implementation of {@link AppIntegrityManagerService}. */ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { Loading Loading @@ -473,9 +475,9 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { SourceStampVerificationResult sourceStampVerificationResult; if (installationPath.isDirectory()) { try { try (Stream<Path> filesList = Files.list(installationPath.toPath())) { List<String> apkFiles = Files.list(installationPath.toPath()) filesList .map(path -> path.toAbsolutePath().toString()) .collect(Collectors.toList()); sourceStampVerificationResult = SourceStampVerifier.verify(apkFiles); Loading Loading
core/java/android/util/apk/SourceStampVerifier.java +37 −25 Original line number Diff line number Diff line Loading @@ -24,6 +24,7 @@ import static android.util.apk.ApkSigningBlockUtils.isSupportedSignatureAlgorith import static android.util.apk.ApkSigningBlockUtils.readLengthPrefixedByteArray; import android.util.Pair; import android.util.Slog; import android.util.jar.StrictJarFile; import libcore.io.IoUtils; Loading Loading @@ -69,6 +70,8 @@ import java.util.zip.ZipEntry; */ public abstract class SourceStampVerifier { private static final String TAG = "SourceStampVerifier"; private static final int APK_SIGNATURE_SCHEME_V2_BLOCK_ID = 0x7109871a; private static final int APK_SIGNATURE_SCHEME_V3_BLOCK_ID = 0xf05368c0; private static final int SOURCE_STAMP_BLOCK_ID = 0x2b09189e; Loading Loading @@ -99,28 +102,31 @@ public abstract class SourceStampVerifier { /** Verifies SourceStamp present in the provided APK. */ public static SourceStampVerificationResult verify(String apkFile) { StrictJarFile apkJar = null; try (RandomAccessFile apk = new RandomAccessFile(apkFile, "r")) { return verify(apk); } catch (IOException e) { // Any exception in reading the APK returns a non-present SourceStamp outcome // without affecting the outcome of any of the other signature schemes. return SourceStampVerificationResult.notPresent(); } } private static SourceStampVerificationResult verify(RandomAccessFile apk) { byte[] sourceStampCertificateDigest; try { sourceStampCertificateDigest = getSourceStampCertificateDigest(apk); apkJar = new StrictJarFile( apkFile, /* verify= */ false, /* signatureSchemeRollbackProtectionsEnforced= */ false); byte[] sourceStampCertificateDigest = getSourceStampCertificateDigest(apkJar); if (sourceStampCertificateDigest == null) { // SourceStamp certificate hash file not found, which means that there is not // SourceStamp present. return SourceStampVerificationResult.notPresent(); } return verify(apk, sourceStampCertificateDigest); } catch (IOException e) { // Any exception in reading the APK returns a non-present SourceStamp outcome // without affecting the outcome of any of the other signature schemes. return SourceStampVerificationResult.notPresent(); } finally { closeApkJar(apkJar); } } private static SourceStampVerificationResult verify( RandomAccessFile apk, byte[] sourceStampCertificateDigest) { try { SignatureInfo signatureInfo = ApkSigningBlockUtils.findSignature(apk, SOURCE_STAMP_BLOCK_ID); Loading Loading @@ -283,22 +289,17 @@ public abstract class SourceStampVerifier { return apkContentDigests; } private static byte[] getSourceStampCertificateDigest(RandomAccessFile apk) throws IOException { StrictJarFile apkJar = new StrictJarFile( apk.getFD(), /* verify= */ false, /* signatureSchemeRollbackProtectionsEnforced= */ false); private static byte[] getSourceStampCertificateDigest(StrictJarFile apkJar) throws IOException { InputStream inputStream = null; try { ZipEntry zipEntry = apkJar.findEntry(SOURCE_STAMP_CERTIFICATE_HASH_ZIP_ENTRY_NAME); if (zipEntry == null) { // SourceStamp certificate hash file not found, which means that there is not // SourceStamp present. return null; } InputStream inputStream = null; ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); try { inputStream = apkJar.getInputStream(zipEntry); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); // Trying to read the certificate digest, which should be less than 1024 bytes. byte[] buffer = new byte[1024]; Loading Loading @@ -327,4 +328,15 @@ public abstract class SourceStampVerifier { } return result.array(); } private static void closeApkJar(StrictJarFile apkJar) { try { if (apkJar == null) { return; } apkJar.close(); } catch (IOException e) { Slog.e(TAG, "Could not close APK jar", e); } } }
services/core/java/com/android/server/integrity/AppIntegrityManagerServiceImpl.java +4 −2 Original line number Diff line number Diff line Loading @@ -73,6 +73,7 @@ import java.io.IOException; import java.io.InputStream; import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.security.cert.CertificateEncodingException; Loading @@ -88,6 +89,7 @@ import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import java.util.stream.Stream; /** Implementation of {@link AppIntegrityManagerService}. */ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { Loading Loading @@ -473,9 +475,9 @@ public class AppIntegrityManagerServiceImpl extends IAppIntegrityManager.Stub { SourceStampVerificationResult sourceStampVerificationResult; if (installationPath.isDirectory()) { try { try (Stream<Path> filesList = Files.list(installationPath.toPath())) { List<String> apkFiles = Files.list(installationPath.toPath()) filesList .map(path -> path.toAbsolutePath().toString()) .collect(Collectors.toList()); sourceStampVerificationResult = SourceStampVerifier.verify(apkFiles); Loading