diff options
author | 2017-11-20 12:48:52 +0000 | |
---|---|---|
committer | 2017-11-21 17:01:39 +0000 | |
commit | 19d19048e46a44f9cd92f9b3c2b45d9603283f15 (patch) | |
tree | e42d13f7541b8f038533d58780fe708745feebd8 | |
parent | 5f52b4dfe539e2c8226e173630645df1285daae5 (diff) |
DevicePolicyManager: Make installed keys user-selectable by default.
After Change-Id: Ibaba2ddd4f94fced1a2a7bfcfb91189302ec7f3a was merged,
KeyChain, by default, made keys installed in it not user-selectable,
which means users could not choose those keys in the Certificate
Selection prompt.
This is the correct behaviour (secure by default), but means the
DevicePolicyManager has to explicitly set keys as user-selectable
to be compatible with the previous behaviour.
This CL does the following:
* Adding an installKeyPair variant to the DevicePolicyManager to
allow specifying user-selectability of the key.
* Make old installKeyPair variants delegate to the new variant,
with the default of setting installed keys user-selectable.
* Modify the DevicePolicyManager service definition and service to
take the extra user-selectability parameter and set the value
in KeyChain.
Note that the reason the CTS test started failing is not related to
this change but a CTS Verifier test should catch the problem this
CL is solving.
Part of the fix for b/69337278
Bug: 69337278
Test: cts-tradefed run commandAndExit cts-dev -a armeabi-v7a -m CtsDevicePolicyManagerTestCases -t com.android.cts.devicepolicy.DeviceOwnerTest#testKeyManagement
Change-Id: Ifc240ed4a20a9d00bc6140dfb45bd1140e1f8260
-rw-r--r-- | api/current.txt | 1 | ||||
-rw-r--r-- | api/system-current.txt | 1 | ||||
-rw-r--r-- | api/test-current.txt | 1 | ||||
-rw-r--r-- | core/java/android/app/admin/DevicePolicyManager.java | 43 | ||||
-rw-r--r-- | core/java/android/app/admin/IDevicePolicyManager.aidl | 3 | ||||
-rw-r--r-- | services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java | 4 |
6 files changed, 50 insertions, 3 deletions
diff --git a/api/current.txt b/api/current.txt index 7e4ee1a51406..f8b9f41e634f 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6371,6 +6371,7 @@ package android.app.admin { method public boolean installCaCert(android.content.ComponentName, byte[]); method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String); method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean); + method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean, boolean); method public boolean isActivePasswordSufficient(); method public boolean isAdminActive(android.content.ComponentName); method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String); diff --git a/api/system-current.txt b/api/system-current.txt index a6e1eabbd638..00681a09e7d8 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -6599,6 +6599,7 @@ package android.app.admin { method public boolean installCaCert(android.content.ComponentName, byte[]); method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String); method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean); + method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean, boolean); method public boolean isActivePasswordSufficient(); method public boolean isAdminActive(android.content.ComponentName); method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String); diff --git a/api/test-current.txt b/api/test-current.txt index f9dd65c6ad14..bc82fbe8cdc9 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -6440,6 +6440,7 @@ package android.app.admin { method public boolean installCaCert(android.content.ComponentName, byte[]); method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String); method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean); + method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate[], java.lang.String, boolean, boolean); method public boolean isActivePasswordSufficient(); method public boolean isAdminActive(android.content.ComponentName); method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index f0226b7e848f..0bca96907988 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -3858,6 +3858,47 @@ public class DevicePolicyManager { */ public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey, @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess) { + return installKeyPair(admin, privKey, certs, alias, requestAccess, true); + } + + /** + * Called by a device or profile owner, or delegated certificate installer, to install a + * certificate chain and corresponding private key for the leaf certificate. All apps within the + * profile will be able to access the certificate chain and use the private key, given direct + * user approval (if the user is allowed to select the private key). + * + * <p>The caller of this API may grant itself access to the certificate and private key + * immediately, without user approval. It is a best practice not to request this unless strictly + * necessary since it opens up additional security vulnerabilities. + * + * <p>Whether this key is offered to the user for approval at all or not depends on the + * {@code isUserSelectable} parameter. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. + * @param privKey The private key to install. + * @param certs The certificate chain to install. The chain should start with the leaf + * certificate and include the chain of trust in order. This will be returned by + * {@link android.security.KeyChain#getCertificateChain}. + * @param alias The private key alias under which to install the certificate. If a certificate + * with that alias already exists, it will be overwritten. + * @param requestAccess {@code true} to request that the calling app be granted access to the + * credentials immediately. Otherwise, access to the credentials will be gated by user + * approval. + * @param isUserSelectable {@code true} to indicate that a user can select this key via the + * Certificate Selection prompt, false to indicate that this key can only be granted + * access by implementing + * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias}. + * @return {@code true} if the keys were installed, {@code false} otherwise. + * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile + * owner. + * @see android.security.KeyChain#getCertificateChain + * @see #setDelegatedScopes + * @see #DELEGATION_CERT_INSTALL + */ + public boolean installKeyPair(@Nullable ComponentName admin, @NonNull PrivateKey privKey, + @NonNull Certificate[] certs, @NonNull String alias, boolean requestAccess, + boolean isUserSelectable) { throwIfParentInstance("installKeyPair"); try { final byte[] pemCert = Credentials.convertToPem(certs[0]); @@ -3868,7 +3909,7 @@ public class DevicePolicyManager { final byte[] pkcs8Key = KeyFactory.getInstance(privKey.getAlgorithm()) .getKeySpec(privKey, PKCS8EncodedKeySpec.class).getEncoded(); return mService.installKeyPair(admin, mContext.getPackageName(), pkcs8Key, pemCert, - pemChain, alias, requestAccess); + pemChain, alias, requestAccess, isUserSelectable); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index be0b9205bcdd..b7740e9e7314 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -162,7 +162,8 @@ interface IDevicePolicyManager { boolean isCaCertApproved(in String alias, int userHandle); boolean installKeyPair(in ComponentName who, in String callerPackage, in byte[] privKeyBuffer, - in byte[] certBuffer, in byte[] certChainBuffer, String alias, boolean requestAccess); + in byte[] certBuffer, in byte[] certChainBuffer, String alias, boolean requestAccess, + boolean isUserSelectable); boolean removeKeyPair(in ComponentName who, in String callerPackage, String alias); void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 2d8a0ee02225..60c36d1b7203 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -4917,7 +4917,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean installKeyPair(ComponentName who, String callerPackage, byte[] privKey, - byte[] cert, byte[] chain, String alias, boolean requestAccess) { + byte[] cert, byte[] chain, String alias, boolean requestAccess, + boolean isUserSelectable) { enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, DELEGATION_CERT_INSTALL); @@ -4935,6 +4936,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (requestAccess) { keyChain.setGrant(callingUid, alias, true); } + keyChain.setUserSelectable(alias, isUserSelectable); return true; } catch (RemoteException e) { Log.e(LOG_TAG, "Installing certificate", e); |