Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 26408ccd authored by Bernhard Bauer's avatar Bernhard Bauer Committed by Robin Lee
Browse files

Add DevicePolicyManager PrivateKey mgmt

Additional device policy API to install keypairs to the keychain
silently.

Bug: 15065444
Change-Id: Idc25774c9ab1a61080290bebd6f5c4f24e6ee2e0
parent 2f67e237
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -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);
+29 −0
Original line number Diff line number Diff line
@@ -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;
@@ -1837,6 +1840,32 @@ public class DevicePolicyManager {
        return false;
    }

    /**
     * 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.
+2 −0
Original line number Diff line number Diff line
@@ -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);

+3 −0
Original line number Diff line number Diff line
@@ -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();
+34 −3
Original line number Diff line number Diff line
@@ -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();