diff options
5 files changed, 69 insertions, 3 deletions
diff --git a/api/current.txt b/api/current.txt index df376c4..f03e2f3 100644 --- a/api/current.txt +++ b/api/current.txt @@ -5453,6 +5453,7 @@ package android.app.admin { method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]); method public boolean hasGrantedPolicy(android.content.ComponentName, int); method public boolean installCaCert(android.content.ComponentName, byte[]); + method public void installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String); 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 8f1343d..4a21913 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -38,6 +38,7 @@ import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; +import android.security.Credentials; import android.service.restrictions.RestrictionsReceiver; import android.util.Log; @@ -49,6 +50,8 @@ import java.io.ByteArrayInputStream; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Proxy; +import java.security.PrivateKey; +import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; @@ -1838,6 +1841,32 @@ public class DevicePolicyManager { } /** + * Called by a device or profile owner to install a certificate and private key pair. The + * keypair will be visible to all apps within the profile. + * + * @param who Which {@link DeviceAdminReceiver} this request is associated with. + * @param privKey The private key to install. + * @param cert The certificate to install. + * @param alias The private key alias under which to install the certificate. If a certificate + * with that alias already exists, it will be overwritten. + * @return {@code true} if the keys were installed, {@code false} otherwise. + */ + public boolean installKeyPair(ComponentName who, PrivateKey privKey, Certificate cert, + String alias) { + try { + final byte[] pemCert = Credentials.convertToPem(cert); + return mService.installKeyPair(who, privKey.getEncoded(), pemCert, alias); + } catch (CertificateException e) { + Log.w(TAG, "Error encoding certificate", e); + } catch (IOException e) { + Log.w(TAG, "Error writing certificate", e); + } catch (RemoteException e) { + Log.w(TAG, "Failed talking with device policy service", e); + } + return false; + } + + /** * Returns the alias of a given CA certificate in the certificate store, or 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 57d8b95..c8e1780 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -126,6 +126,8 @@ interface IDevicePolicyManager { void uninstallCaCert(in ComponentName admin, in String alias); void enforceCanManageCaCerts(in ComponentName admin); + boolean installKeyPair(in ComponentName who, in byte[] privKeyBuffer, in byte[] certBuffer, String alias); + void addPersistentPreferredActivity(in ComponentName admin, in IntentFilter filter, in ComponentName activity); void clearPackagePersistentPreferredActivities(in ComponentName admin, String packageName); diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl index a93891a..20c94c5 100644 --- a/keystore/java/android/security/IKeyChainService.aidl +++ b/keystore/java/android/security/IKeyChainService.aidl @@ -31,6 +31,9 @@ interface IKeyChainService { // APIs used by CertInstaller void installCaCertificate(in byte[] caCertificate); + // APIs used by DevicePolicyManager + boolean installKeyPair(in byte[] privateKey, in byte[] userCert, String alias); + // APIs used by Settings boolean deleteCaCertificate(String alias); boolean reset(); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 628559b..8e82e2a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -44,13 +44,13 @@ import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; import android.content.pm.UserInfo; +import android.database.ContentObserver; +import android.hardware.usb.UsbManager; import android.media.AudioManager; import android.media.IAudioService; import android.net.ConnectivityManager; -import android.net.Uri; -import android.database.ContentObserver; -import android.hardware.usb.UsbManager; import android.net.ProxyInfo; +import android.net.Uri; import android.os.Binder; import android.os.Bundle; import android.os.Environment; @@ -69,6 +69,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.security.Credentials; +import android.security.IKeyChainService; import android.security.KeyChain; import android.security.KeyChain.KeyChainConnection; import android.util.Log; @@ -110,6 +111,7 @@ import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.PrintWriter; +import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; @@ -2829,6 +2831,35 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override + public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, String alias) { + if (who == null) { + throw new NullPointerException("ComponentName is null"); + } + synchronized (this) { + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + } + final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); + final long id = Binder.clearCallingIdentity(); + try { + final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle); + try { + IKeyChainService keyChain = keyChainConnection.getService(); + return keyChain.installKeyPair(privKey, cert, alias); + } catch (RemoteException e) { + Log.e(LOG_TAG, "Installing certificate", e); + } finally { + keyChainConnection.close(); + } + } catch (InterruptedException e) { + Log.w(LOG_TAG, "Interrupted while installing certificate", e); + Thread.currentThread().interrupt(); + } finally { + Binder.restoreCallingIdentity(id); + } + return false; + } + void wipeDataLocked(int flags) { // If the SD card is encrypted and non-removable, we have to force a wipe. boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted(); |