diff options
| author | 2017-12-20 08:43:56 +0000 | |
|---|---|---|
| committer | 2017-12-20 08:43:56 +0000 | |
| commit | a82824272cc0d7c522fed96cf9d0b97dc2087a33 (patch) | |
| tree | adf8531adac9ba9f1fa44811d6f0212990147bf5 | |
| parent | 5d35adf0e2e1589d6aee5b4d4c047a948074f328 (diff) | |
| parent | ecf0f22e5831832afb48c86abfaa81234c8db619 (diff) | |
Merge "DPM: Implement installing certificates for generated keys"
6 files changed, 82 insertions, 0 deletions
diff --git a/api/current.txt b/api/current.txt index 38ece14196d2..7c8e5e75ed2d 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6451,6 +6451,7 @@ package android.app.admin { method public void setDeviceOwnerLockScreenInfo(android.content.ComponentName, java.lang.CharSequence); method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String); method public void setKeepUninstalledPackages(android.content.ComponentName, java.util.List<java.lang.String>); + method public boolean setKeyPairCertificate(android.content.ComponentName, java.lang.String, java.util.List<java.security.cert.Certificate>, boolean); method public boolean setKeyguardDisabled(android.content.ComponentName, boolean); method public void setKeyguardDisabledFeatures(android.content.ComponentName, int); method public void setLockTaskFeatures(android.content.ComponentName, int); diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 9ad990af3bb5..98162976173d 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -4174,6 +4174,52 @@ public class DevicePolicyManager { return null; } + + /** + * Called by a device or profile owner, or delegated certificate installer, to associate + * certificates with a key pair that was generated using {@link #generateKeyPair}, and + * set whether the key is available for the user to choose in the certificate selection + * prompt. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. + * @param alias The private key alias under which to install the certificate. The {@code alias} + * should denote an existing private key. If a certificate with that alias already + * exists, it will be overwritten. + * @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 isUserSelectable {@code true} to indicate that a user can select this key via the + * certificate selection prompt, {@code false} to indicate that this key can only be + * granted access by implementing + * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias}. + * @return {@code true} if the provided {@code alias} exists and the certificates has been + * successfully associated with it, {@code false} otherwise. + * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile + * owner, or {@code admin} is null but the calling application is not a delegated + * certificate installer. + */ + public boolean setKeyPairCertificate(@Nullable ComponentName admin, + @NonNull String alias, @NonNull List<Certificate> certs, boolean isUserSelectable) { + throwIfParentInstance("setKeyPairCertificate"); + try { + final byte[] pemCert = Credentials.convertToPem(certs.get(0)); + byte[] pemChain = null; + if (certs.size() > 1) { + pemChain = Credentials.convertToPem( + certs.subList(1, certs.size()).toArray(new Certificate[0])); + } + return mService.setKeyPairCertificate(admin, mContext.getPackageName(), alias, pemCert, + pemChain, isUserSelectable); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (CertificateException | IOException e) { + Log.w(TAG, "Could not pem-encode certificate", e); + } + return false; + } + + /** * @return the alias of a given CA certificate in the certificate store, or {@code null} if it * doesn't exist. diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index f4cd797438ae..5b02c221332a 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -175,6 +175,8 @@ interface IDevicePolicyManager { boolean generateKeyPair(in ComponentName who, in String callerPackage, in String algorithm, in ParcelableKeyGenParameterSpec keySpec, out KeymasterCertificateChain attestationChain); + boolean setKeyPairCertificate(in ComponentName who, in String callerPackage, in String alias, + in byte[] certBuffer, in byte[] certChainBuffer, boolean isUserSelectable); void choosePrivateKeyAlias(int uid, in Uri uri, in String alias, IBinder aliasCallback); void setDelegatedScopes(in ComponentName who, in String delegatePackage, in List<String> scopes); diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl index eca52cc3e8b6..7c7417dfaaac 100644 --- a/keystore/java/android/security/IKeyChainService.aidl +++ b/keystore/java/android/security/IKeyChainService.aidl @@ -35,6 +35,7 @@ interface IKeyChainService { boolean generateKeyPair(in String algorithm, in ParcelableKeyGenParameterSpec spec); boolean attestKey(in String alias, in byte[] challenge, out KeymasterCertificateChain chain); + boolean setKeyPairCertificate(String alias, in byte[] userCert, in byte[] certChain); // APIs used by CertInstaller and DevicePolicyManager String installCaCertificate(in byte[] caCertificate); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index da42dc936132..e55d4ea35739 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -91,4 +91,9 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { public boolean isUsingUnifiedPassword(ComponentName who) { return true; } + + public boolean setKeyPairCertificate(ComponentName who, String callerPackage, String alias, + byte[] cert, byte[] chain, boolean isUserSelectable) { + return false; + } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index d1a93d06b624..387818be6480 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -5154,6 +5154,33 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + public boolean setKeyPairCertificate(ComponentName who, String callerPackage, String alias, + byte[] cert, byte[] chain, boolean isUserSelectable) { + enforceCanManageScope(who, callerPackage, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER, + DELEGATION_CERT_INSTALL); + + final int callingUid = mInjector.binderGetCallingUid(); + final long id = mInjector.binderClearCallingIdentity(); + try (final KeyChainConnection keyChainConnection = + KeyChain.bindAsUser(mContext, UserHandle.getUserHandleForUid(callingUid))) { + IKeyChainService keyChain = keyChainConnection.getService(); + if (!keyChain.setKeyPairCertificate(alias, cert, chain)) { + return false; + } + keyChain.setUserSelectable(alias, isUserSelectable); + return true; + } catch (InterruptedException e) { + Log.w(LOG_TAG, "Interrupted while setting keypair certificate", e); + Thread.currentThread().interrupt(); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Failed setting keypair certificate", e); + } finally { + mInjector.binderRestoreCallingIdentity(id); + } + return false; + } + + @Override public void choosePrivateKeyAlias(final int uid, final Uri uri, final String alias, final IBinder response) { // Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers. |