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

Commit 5023e1fb authored by Max Bires's avatar Max Bires Committed by Gerrit Code Review
Browse files

Merge "Fixing the race condition in GenerateRkpKey"

parents ce7dffbc 5e43390b
Loading
Loading
Loading
Loading
+50 −19
Original line number Diff line number Diff line
@@ -22,6 +22,10 @@ import android.content.Intent;
import android.content.ServiceConnection;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * GenerateKey is a helper class to handle interactions between Keystore and the RemoteProvisioner
@@ -41,14 +45,25 @@ import android.os.RemoteException;
 * @hide
 */
public class GenerateRkpKey {
    private static final String TAG = "GenerateRkpKey";

    private static final int NOTIFY_EMPTY = 0;
    private static final int NOTIFY_KEY_GENERATED = 1;
    private static final int TIMEOUT_MS = 1000;

    private IGenerateRkpKeyService mBinder;
    private Context mContext;
    private CountDownLatch mCountDownLatch;

    private ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName className, IBinder service) {
            mBinder = IGenerateRkpKeyService.Stub.asInterface(service);
            mCountDownLatch.countDown();
        }

        @Override public void onBindingDied(ComponentName className) {
            mCountDownLatch.countDown();
        }

        @Override
@@ -64,36 +79,52 @@ public class GenerateRkpKey {
        mContext = context;
    }

    /**
     * Fulfills the use case of (2) described in the class documentation. Blocks until the
     * RemoteProvisioner application can get new attestation keys signed by the server.
     */
    public void notifyEmpty(int securityLevel) throws RemoteException {
    private void bindAndSendCommand(int command, int securityLevel) throws RemoteException {
        Intent intent = new Intent(IGenerateRkpKeyService.class.getName());
        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
        if (comp == null) {
            // On a system that does not use RKP, the RemoteProvisioner app won't be installed.
            return;
        }
        intent.setComponent(comp);
        if (comp == null || !mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
            throw new RemoteException("Failed to bind to GenerateKeyService");
        mCountDownLatch = new CountDownLatch(1);
        if (!mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
            throw new RemoteException("Failed to bind to GenerateRkpKeyService");
        }
        try {
            mCountDownLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS);
        } catch (InterruptedException e) {
            Log.e(TAG, "Interrupted: ", e);
        }
        if (mBinder != null) {
            switch (command) {
                case NOTIFY_EMPTY:
                    mBinder.generateKey(securityLevel);
                    break;
                case NOTIFY_KEY_GENERATED:
                    mBinder.notifyKeyGenerated(securityLevel);
                    break;
                default:
                    Log.e(TAG, "Invalid case for command");
            }
        } else {
            Log.e(TAG, "Binder object is null; failed to bind to GenerateRkpKeyService.");
        }
        mContext.unbindService(mConnection);
    }

    /**
     * FUlfills the use case of (1) described in the class documentation. Non blocking call.
     * Fulfills the use case of (2) described in the class documentation. Blocks until the
     * RemoteProvisioner application can get new attestation keys signed by the server.
     */
    public void notifyEmpty(int securityLevel) throws RemoteException {
        bindAndSendCommand(NOTIFY_EMPTY, securityLevel);
    }

    /**
     * Fulfills the use case of (1) described in the class documentation. Non blocking call.
     */
    public void notifyKeyGenerated(int securityLevel) throws RemoteException {
        Intent intent = new Intent(IGenerateRkpKeyService.class.getName());
        ComponentName comp = intent.resolveSystemService(mContext.getPackageManager(), 0);
        intent.setComponent(comp);
        if (comp == null || !mContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)) {
            throw new RemoteException("Failed to bind to GenerateKeyService");
        }
        if (mBinder != null) {
            mBinder.notifyKeyGenerated(securityLevel);
        }
        mContext.unbindService(mConnection);
        bindAndSendCommand(NOTIFY_KEY_GENERATED, securityLevel);
    }
}
+1 −1
Original line number Diff line number Diff line
@@ -580,7 +580,7 @@ public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGenerato
            } catch (RemoteException e) {
                // This is not really an error state, and necessarily does not apply to non RKP
                // systems or hybrid systems where RKP is not currently turned on.
                Log.d(TAG, "Couldn't connect to the RemoteProvisioner backend.");
                Log.d(TAG, "Couldn't connect to the RemoteProvisioner backend.", e);
            }
            success = true;
            return new KeyPair(publicKey, publicKey.getPrivateKey());