Verify permissions of downloaded apk

This commit is contained in:
Dominik Schürmann 2016-06-08 13:54:56 +02:00
parent 1652c32d51
commit 4bed9d67c5
3 changed files with 39 additions and 13 deletions

View File

@ -5,12 +5,12 @@ import android.content.ContentValues;
import android.database.Cursor;
import android.os.Build;
import android.os.Parcelable;
import android.util.Log;
import org.fdroid.fdroid.Utils;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
public class Apk extends ValueObject implements Comparable<Apk> {
@ -145,7 +145,7 @@ public class Apk extends ValueObject implements Comparable<Apk> {
public ArrayList<String> getFullPermissionList() {
if (this.permissions == null) {
return null;
return new ArrayList<>();
}
ArrayList<String> permissionsFull = new ArrayList<>();
@ -157,13 +157,13 @@ public class Apk extends ValueObject implements Comparable<Apk> {
public String[] getFullPermissionsArray() {
ArrayList<String> fullPermissions = getFullPermissionList();
if (fullPermissions == null) {
return null;
}
return fullPermissions.toArray(new String[fullPermissions.size()]);
}
public HashSet<String> getFullPermissionsSet() {
return new HashSet<>(getFullPermissionList());
}
/**
* It appears that the default Android permissions in android.Manifest.permissions
* are prefixed with "android.permission." and then the constant name.

View File

@ -23,31 +23,37 @@ import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.util.Log;
import org.apache.commons.io.FileUtils;
import org.fdroid.fdroid.Hasher;
import org.fdroid.fdroid.Utils;
import org.fdroid.fdroid.data.Apk;
import org.fdroid.fdroid.data.SanitizedFile;
import java.io.File;
import java.io.IOException;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashSet;
public class ApkVerifier {
private static final String TAG = "ApkVerifier";
Context context;
Uri localApkUri;
Apk apk;
Apk expectedApk;
PackageManager pm;
ApkVerifier(Context context, Uri localApkUri, Apk apk) {
ApkVerifier(Context context, Uri localApkUri, Apk expectedApk) {
this.context = context;
this.localApkUri = localApkUri;
this.apk = apk;
this.expectedApk = expectedApk;
this.pm = context.getPackageManager();
}
public void basicVerify() throws ApkVerificationException {
public void verifyApk() throws ApkVerificationException {
PackageInfo localApkInfo = pm.getPackageArchiveInfo(
localApkUri.getPath(), PackageManager.GET_PERMISSIONS);
if (localApkInfo == null) {
@ -55,13 +61,33 @@ public class ApkVerifier {
}
// check if the apk has the expected packageName
if (localApkInfo.packageName == null || !apk.packageName.equals(localApkInfo.packageName)) {
if (localApkInfo.packageName == null || !localApkInfo.packageName.equals(expectedApk.packageName)) {
throw new ApkVerificationException("apk has unexpected packageName!");
}
if (localApkInfo.versionCode < 0) {
throw new ApkVerificationException("apk has no valid versionCode!");
}
// verify permissions, important for unattended installer
HashSet<String> localPermissions = getLocalPermissionsSet(localApkInfo);
HashSet<String> expectedPermissions = expectedApk.getFullPermissionsSet();
Utils.debugLog(TAG, "localPermissions: " + localPermissions);
Utils.debugLog(TAG, "expectedPermissions: " + expectedPermissions);
if (!localPermissions.equals(expectedPermissions)) {
throw new ApkVerificationException("permissions of apk not equals expected permissions!");
}
// TODO: check target sdk
}
private HashSet<String> getLocalPermissionsSet(PackageInfo localApkInfo) {
String[] localPermissions = localApkInfo.requestedPermissions;
if (localPermissions == null) {
return new HashSet<>();
}
return new HashSet<>(Arrays.asList(localApkInfo.requestedPermissions));
}
public Uri getSafeUri() throws ApkVerificationException {
@ -77,7 +103,7 @@ public class ApkVerifier {
sanitizedApkFile = SanitizedFile.knownSanitized(File.createTempFile("install-", ".apk",
context.getFilesDir()));
FileUtils.copyFile(apkFile, sanitizedApkFile);
if (!verifyApkFile(sanitizedApkFile, apk.hash, apk.hashType)) {
if (!verifyApkFile(sanitizedApkFile, expectedApk.hash, expectedApk.hashType)) {
FileUtils.deleteQuietly(apkFile);
throw new ApkVerificationException(apkFile + " failed to verify!");
}

View File

@ -241,7 +241,7 @@ public class InstallManagerService extends Service {
Uri sanitizedUri;
try {
ApkVerifier apkVerifier = new ApkVerifier(context, localApkUri, apk);
apkVerifier.basicVerify();
apkVerifier.verifyApk();
sanitizedUri = apkVerifier.getSafeUri();
} catch (ApkVerifier.ApkVerificationException e) {
Log.e(TAG, "ApkVerifier failed", e);