diff options
author | Hai Zhang <zhanghai@google.com> | 2021-11-02 13:17:33 -0700 |
---|---|---|
committer | Hai Zhang <zhanghai@google.com> | 2021-11-05 20:35:21 +0000 |
commit | a357af90009374c38eaddedc734ca6af3c4e73f8 (patch) | |
tree | d997767c6b350f0fe7bc131b076e206ec9be1bf6 /PermissionController/src/com/android/permissioncontroller/role | |
parent | a148be8bda93a0f902c3f6793eaa8a866bb40f8e (diff) | |
download | Permission-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.md | 5 | ||||
-rw-r--r-- | PermissionController/src/com/android/permissioncontroller/role/model/Role.java | 68 |
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; } /** |