140 lines
5.5 KiB
Java
140 lines
5.5 KiB
Java
package androidx.core.content.pm;
|
|
|
|
import android.content.pm.PackageInfo;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.Signature;
|
|
import android.content.pm.SigningInfo;
|
|
import android.os.Build;
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
import androidx.annotation.RequiresApi;
|
|
import androidx.annotation.Size;
|
|
import c.d.b.a.a;
|
|
import java.security.MessageDigest;
|
|
import java.security.NoSuchAlgorithmException;
|
|
import java.util.Arrays;
|
|
import java.util.Collections;
|
|
import java.util.Iterator;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
public final class PackageInfoCompat {
|
|
|
|
@RequiresApi(28)
|
|
public static class Api28Impl {
|
|
private Api28Impl() {
|
|
}
|
|
|
|
@Nullable
|
|
public static Signature[] getApkContentsSigners(@NonNull SigningInfo signingInfo) {
|
|
return signingInfo.getApkContentsSigners();
|
|
}
|
|
|
|
@Nullable
|
|
public static Signature[] getSigningCertificateHistory(@NonNull SigningInfo signingInfo) {
|
|
return signingInfo.getSigningCertificateHistory();
|
|
}
|
|
|
|
public static boolean hasMultipleSigners(@NonNull SigningInfo signingInfo) {
|
|
return signingInfo.hasMultipleSigners();
|
|
}
|
|
|
|
public static boolean hasSigningCertificate(@NonNull PackageManager packageManager, @NonNull String str, @NonNull byte[] bArr, int i) {
|
|
return packageManager.hasSigningCertificate(str, bArr, i);
|
|
}
|
|
}
|
|
|
|
private PackageInfoCompat() {
|
|
}
|
|
|
|
private static boolean byteArrayContains(@NonNull byte[][] bArr, @NonNull byte[] bArr2) {
|
|
for (byte[] bArr3 : bArr) {
|
|
if (Arrays.equals(bArr2, bArr3)) {
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
private static byte[] computeSHA256Digest(byte[] bArr) {
|
|
try {
|
|
return MessageDigest.getInstance("SHA256").digest(bArr);
|
|
} catch (NoSuchAlgorithmException e) {
|
|
throw new RuntimeException("Device doesn't support SHA256 cert checking", e);
|
|
}
|
|
}
|
|
|
|
public static long getLongVersionCode(@NonNull PackageInfo packageInfo) {
|
|
return Build.VERSION.SDK_INT >= 28 ? packageInfo.getLongVersionCode() : (long) packageInfo.versionCode;
|
|
}
|
|
|
|
@NonNull
|
|
public static List<Signature> getSignatures(@NonNull PackageManager packageManager, @NonNull String str) throws PackageManager.NameNotFoundException {
|
|
Signature[] signatureArr;
|
|
if (Build.VERSION.SDK_INT >= 28) {
|
|
SigningInfo signingInfo = packageManager.getPackageInfo(str, 134217728).signingInfo;
|
|
signatureArr = Api28Impl.hasMultipleSigners(signingInfo) ? Api28Impl.getApkContentsSigners(signingInfo) : Api28Impl.getSigningCertificateHistory(signingInfo);
|
|
} else {
|
|
signatureArr = packageManager.getPackageInfo(str, 64).signatures;
|
|
}
|
|
return signatureArr == null ? Collections.emptyList() : Arrays.asList(signatureArr);
|
|
}
|
|
|
|
public static boolean hasSignatures(@NonNull PackageManager packageManager, @NonNull String str, @NonNull @Size(min = 1) Map<byte[], Integer> map, boolean z2) throws PackageManager.NameNotFoundException {
|
|
if (map.isEmpty()) {
|
|
return false;
|
|
}
|
|
Set<byte[]> keySet = map.keySet();
|
|
for (byte[] bArr : keySet) {
|
|
if (bArr != null) {
|
|
Integer num = map.get(bArr);
|
|
if (num != null) {
|
|
int intValue = num.intValue();
|
|
if (!(intValue == 0 || intValue == 1)) {
|
|
throw new IllegalArgumentException("Unsupported certificate type " + num + " when verifying " + str);
|
|
}
|
|
} else {
|
|
throw new IllegalArgumentException(a.u("Type must be specified for cert when verifying ", str));
|
|
}
|
|
} else {
|
|
throw new IllegalArgumentException(a.u("Cert byte array cannot be null when verifying ", str));
|
|
}
|
|
}
|
|
List<Signature> signatures = getSignatures(packageManager, str);
|
|
if (z2 || Build.VERSION.SDK_INT < 28) {
|
|
if (signatures.size() != 0 && map.size() <= signatures.size() && (!z2 || map.size() == signatures.size())) {
|
|
byte[][] bArr2 = null;
|
|
if (map.containsValue(1)) {
|
|
bArr2 = new byte[signatures.size()][];
|
|
for (int i = 0; i < signatures.size(); i++) {
|
|
bArr2[i] = computeSHA256Digest(signatures.get(i).toByteArray());
|
|
}
|
|
}
|
|
Iterator<byte[]> it = keySet.iterator();
|
|
if (it.hasNext()) {
|
|
byte[] next = it.next();
|
|
Integer num2 = map.get(next);
|
|
int intValue2 = num2.intValue();
|
|
if (intValue2 != 0) {
|
|
if (intValue2 != 1) {
|
|
throw new IllegalArgumentException("Unsupported certificate type " + num2);
|
|
} else if (!byteArrayContains(bArr2, next)) {
|
|
return false;
|
|
}
|
|
} else if (!signatures.contains(new Signature(next))) {
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
for (byte[] bArr3 : keySet) {
|
|
if (!Api28Impl.hasSigningCertificate(packageManager, str, bArr3, map.get(bArr3).intValue())) {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
}
|