summaryrefslogtreecommitdiff
path: root/PermissionController/src/com/android/permissioncontroller/role
diff options
context:
space:
mode:
authorHai Zhang <zhanghai@google.com>2021-11-02 13:17:33 -0700
committerHai Zhang <zhanghai@google.com>2021-11-05 20:35:21 +0000
commita357af90009374c38eaddedc734ca6af3c4e73f8 (patch)
treed997767c6b350f0fe7bc131b076e206ec9be1bf6 /PermissionController/src/com/android/permissioncontroller/role
parenta148be8bda93a0f902c3f6793eaa8a866bb40f8e (diff)
downloadPermission-a357af90009374c38eaddedc734ca6af3c4e73f8.tar.gz
Support signing certificate for default holder config.
The package name and an optional signing certificate is separated by a colon (`:`). Fixes: 190703786 Test: Manual Test: Clean flash with a default holder config set to a correct certificate and ensure role is granted. Test: Clean flash with a default holder config set to an incorrect certificate and ensure role isn't granted. Change-Id: I5ab6950a5bdc0fd62c5e49c238c422b4579e55dc
Diffstat (limited to 'PermissionController/src/com/android/permissioncontroller/role')
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/Role.md5
-rw-r--r--PermissionController/src/com/android/permissioncontroller/role/model/Role.java68
2 files changed, 54 insertions, 19 deletions
diff --git a/PermissionController/src/com/android/permissioncontroller/role/Role.md b/PermissionController/src/com/android/permissioncontroller/role/Role.md
index 1e2c5a13c..acf8ec649 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/Role.md
+++ b/PermissionController/src/com/android/permissioncontroller/role/Role.md
@@ -46,7 +46,10 @@ role behavior in Java code, e.g. `SmsRoleBehavior`. This can be useful when the
express certain behavior specific to the role.
- `defaultHolders`: Optional name of a system config resource that designates the default holders of
the role, e.g. `config_defaultSms`. If the role is not exclusive, multiple package names can be
-specified by separating them with a semicolon (`;`).
+specified by separating them with a semicolon (`;`). Each package name can also be optionally
+followed by a SHA-256 digest of the expected signing certificate to allow specifying non-system
+apps, separated by a colon (`:`) with the package name, for instance
+`com.example.normalapp:sha256;com.example.systemapp`.
- `description`: The string resource for the description of the role, e.g.
`@string/role_sms_description`, which says "Apps that allow you to use your phone number to send and
receive short text messages, photos, videos, and more". For default apps, this string will appear in
diff --git a/PermissionController/src/com/android/permissioncontroller/role/model/Role.java b/PermissionController/src/com/android/permissioncontroller/role/model/Role.java
index 884f7d929..8f8b845cb 100644
--- a/PermissionController/src/com/android/permissioncontroller/role/model/Role.java
+++ b/PermissionController/src/com/android/permissioncontroller/role/model/Role.java
@@ -24,6 +24,7 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.SharedLibraryInfo;
+import android.content.pm.Signature;
import android.content.res.Resources;
import android.os.Build;
import android.os.Process;
@@ -76,7 +77,9 @@ public class Role {
private static final String PACKAGE_NAME_ANDROID_SYSTEM = "android";
- private static final String PACKAGE_NAME_SEPARATOR = ";";
+ private static final String DEFAULT_HOLDER_SEPARATOR = ";";
+
+ private static final String CERTIFICATE_SEPARATOR = ":";
/**
* The name of this role. Must be unique.
@@ -432,28 +435,29 @@ public class Role {
return Collections.emptyList();
}
- String resourceValue;
+ String defaultHolders;
try {
- resourceValue = resources.getString(resourceId);
+ defaultHolders = resources.getString(resourceId);
} catch (Resources.NotFoundException e) {
Log.w(LOG_TAG, "Cannot get resource for default holder: " + mDefaultHoldersResourceName,
e);
return Collections.emptyList();
}
- if (TextUtils.isEmpty(resourceValue)) {
+ if (TextUtils.isEmpty(defaultHolders)) {
return Collections.emptyList();
}
if (isExclusive()) {
- if (!isDefaultHolderQualified(resourceValue, context)) {
+ String packageName = getQualifiedDefaultHolderPackageName(defaultHolders, context);
+ if (packageName == null) {
return Collections.emptyList();
}
- return Collections.singletonList(resourceValue);
+ return Collections.singletonList(packageName);
} else {
- String[] resourcePackageNames = resourceValue.split(PACKAGE_NAME_SEPARATOR);
List<String> packageNames = new ArrayList<>();
- for (String packageName : resourcePackageNames) {
- if (isDefaultHolderQualified(packageName, context)) {
+ for (String defaultHolder : defaultHolders.split(DEFAULT_HOLDER_SEPARATOR)) {
+ String packageName = getQualifiedDefaultHolderPackageName(defaultHolders, context);
+ if (packageName != null) {
packageNames.add(packageName);
}
}
@@ -461,20 +465,48 @@ public class Role {
}
}
- private boolean isDefaultHolderQualified(@NonNull String packageName,
+ @Nullable
+ private String getQualifiedDefaultHolderPackageName(@NonNull String defaultHolder,
@NonNull Context context) {
- ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
- if (applicationInfo == null) {
- Log.w(LOG_TAG, "Cannot get ApplicationInfo for default holder: " + packageName);
- return false;
+ String packageName;
+ byte[] certificate;
+ int certificateSeparatorIndex = defaultHolder.indexOf(CERTIFICATE_SEPARATOR);
+ if (certificateSeparatorIndex != -1) {
+ packageName = defaultHolder.substring(0, certificateSeparatorIndex);
+ String certificateString = defaultHolder.substring(certificateSeparatorIndex + 1);
+ try {
+ certificate = new Signature(certificateString).toByteArray();
+ } catch (IllegalArgumentException e) {
+ Log.w(LOG_TAG, "Cannot parse signing certificate: " + defaultHolder, e);
+ return null;
+ }
+ } else {
+ packageName = defaultHolder;
+ certificate = null;
}
- if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
- Log.w(LOG_TAG, "Default holder is not a system app: " + packageName);
- return false;
+ if (certificate != null) {
+ PackageManager packageManager = context.getPackageManager();
+ if (!packageManager.hasSigningCertificate(packageName, certificate,
+ PackageManager.CERT_INPUT_SHA256)) {
+ Log.w(LOG_TAG, "Default holder doesn't have required signing certificate: "
+ + defaultHolder);
+ return null;
+ }
+ } else {
+ ApplicationInfo applicationInfo = PackageUtils.getApplicationInfo(packageName, context);
+ if (applicationInfo == null) {
+ Log.w(LOG_TAG, "Cannot get ApplicationInfo for default holder: " + packageName);
+ return null;
+ }
+ if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 0) {
+ Log.w(LOG_TAG, "Default holder didn't specify a signing certificate and isn't a"
+ + " system app: " + packageName);
+ return null;
+ }
}
- return true;
+ return packageName;
}
/**