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

Commit eff37cca authored by Janis Danisevskis's avatar Janis Danisevskis Committed by Android (Google) Code Review
Browse files

Merge "Keystore.java: Make apps tolerant to keystore crashes"

parents 23110321 c9277ffd
Loading
Loading
Loading
Loading
+115 −43
Original line number Diff line number Diff line
@@ -17,7 +17,6 @@
package android.security;

import android.annotation.UnsupportedAppUsage;
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.Application;
import android.app.KeyguardManager;
@@ -45,24 +44,24 @@ import android.security.keystore.KeyExpiredException;
import android.security.keystore.KeyNotYetValidException;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
import android.security.keystore.KeystoreResponse;
import android.security.keystore.StrongBoxUnavailableException;
import android.security.keystore.UserNotAuthenticatedException;
import android.util.Log;

import com.android.org.bouncycastle.asn1.ASN1InputStream;
import com.android.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
import java.math.BigInteger;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

import sun.security.util.ObjectIdentifier;
import sun.security.x509.AlgorithmId;

@@ -492,8 +491,9 @@ public class KeyStore {
    }

    public boolean addRngEntropy(byte[] data, int flags) {
        try {
        KeystoreResultPromise promise = new KeystoreResultPromise();
        try {
            mBinder.asBinder().linkToDeath(promise, 0);
            int errorCode = mBinder.addRngEntropy(promise, data, flags);
            if (errorCode == NO_ERROR) {
                return promise.getFuture().get().getErrorCode() == NO_ERROR;
@@ -506,6 +506,8 @@ public class KeyStore {
        } catch (ExecutionException | InterruptedException e) {
            Log.e(TAG, "AddRngEntropy completed with exception", e);
            return false;
        } finally {
            mBinder.asBinder().unlinkToDeath(promise, 0);
        }
    }

@@ -537,7 +539,8 @@ public class KeyStore {
    }

    private class KeyCharacteristicsPromise
    extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub {
            extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub
            implements IBinder.DeathRecipient {
        final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
                new CompletableFuture<KeyCharacteristicsCallbackResult>();
        @Override
@@ -550,19 +553,30 @@ public class KeyStore {
        public final CompletableFuture<KeyCharacteristicsCallbackResult> getFuture() {
            return future;
        }
        @Override
        public void binderDied() {
            future.completeExceptionally(new RemoteException("Keystore died"));
        }
    };

    private int generateKeyInternal(String alias, KeymasterArguments args, byte[] entropy, int uid,
            int flags, KeyCharacteristics outCharacteristics)
                    throws RemoteException, ExecutionException, InterruptedException {
        KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
        int error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
        int error = NO_ERROR;
        KeyCharacteristicsCallbackResult result = null;
        try {
            mBinder.asBinder().linkToDeath(promise, 0);
            error = mBinder.generateKey(promise, alias, args, entropy, uid, flags);
            if (error != NO_ERROR) {
                Log.e(TAG, "generateKeyInternal failed on request " + error);
                return error;
            }
            result = promise.getFuture().get();
        } finally {
            mBinder.asBinder().unlinkToDeath(promise, 0);
        }

        KeyCharacteristicsCallbackResult result = promise.getFuture().get();
        error = result.getKeystoreResponse().getErrorCode();
        if (error != NO_ERROR) {
            Log.e(TAG, "generateKeyInternal failed on response " + error);
@@ -604,10 +618,12 @@ public class KeyStore {

    public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
            int uid, KeyCharacteristics outCharacteristics) {
        KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
        try {
            mBinder.asBinder().linkToDeath(promise, 0);
            clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
            appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
            KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();

            int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
            if (error != NO_ERROR) return error;

@@ -625,6 +641,8 @@ public class KeyStore {
        } catch (ExecutionException | InterruptedException e) {
            Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
            return SYSTEM_ERROR;
        } finally {
            mBinder.asBinder().unlinkToDeath(promise, 0);
        }
    }

@@ -637,10 +655,13 @@ public class KeyStore {
            int uid, int flags, KeyCharacteristics outCharacteristics)
                    throws RemoteException, ExecutionException, InterruptedException {
        KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
        mBinder.asBinder().linkToDeath(promise, 0);
        try {
            int error = mBinder.importKey(promise, alias, args, format, keyData, uid, flags);
            if (error != NO_ERROR) return error;

            KeyCharacteristicsCallbackResult result = promise.getFuture().get();

            error = result.getKeystoreResponse().getErrorCode();
            if (error != NO_ERROR) return error;

@@ -648,6 +669,9 @@ public class KeyStore {
            if (characteristics == null) return SYSTEM_ERROR;
            outCharacteristics.shallowCopyFrom(characteristics);
            return NO_ERROR;
        } finally {
            mBinder.asBinder().unlinkToDeath(promise, 0);
        }
    }

    public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
@@ -738,11 +762,15 @@ public class KeyStore {
            KeyCharacteristics outCharacteristics)
                    throws RemoteException, ExecutionException, InterruptedException {
        KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
        int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
                maskingKey, args, rootSid, fingerprintSid);
        mBinder.asBinder().linkToDeath(promise, 0);
        try {
            KeyCharacteristicsCallbackResult result = null;
            int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey,
                    wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
            if (error != NO_ERROR) return error;

        KeyCharacteristicsCallbackResult result = promise.getFuture().get();
            KeyCharacteristicsCallbackResult esult = promise.getFuture().get();

            error = result.getKeystoreResponse().getErrorCode();
            if (error != NO_ERROR) return error;

@@ -750,6 +778,9 @@ public class KeyStore {
            if (characteristics == null) return SYSTEM_ERROR;
            outCharacteristics.shallowCopyFrom(characteristics);
            return NO_ERROR;
        } finally {
            mBinder.asBinder().unlinkToDeath(promise, 0);
        }
    }

    public int importWrappedKey(String wrappedKeyAlias, byte[] wrappedKey,
@@ -776,7 +807,8 @@ public class KeyStore {
    }

    private class ExportKeyPromise
    extends android.security.keystore.IKeystoreExportKeyCallback.Stub {
            extends android.security.keystore.IKeystoreExportKeyCallback.Stub
            implements IBinder.DeathRecipient {
        final private CompletableFuture<ExportResult> future = new CompletableFuture<ExportResult>();
        @Override
        public void onFinished(ExportResult exportKeyResult) throws android.os.RemoteException {
@@ -785,14 +817,19 @@ public class KeyStore {
        public final CompletableFuture<ExportResult> getFuture() {
            return future;
        }
        @Override
        public void binderDied() {
            future.completeExceptionally(new RemoteException("Keystore died"));
        }
    };

    public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
            KeymasterBlob appId, int uid) {
        ExportKeyPromise promise = new ExportKeyPromise();
        try {
            mBinder.asBinder().linkToDeath(promise, 0);
            clientId = clientId != null ? clientId : new KeymasterBlob(new byte[0]);
            appId = appId != null ? appId : new KeymasterBlob(new byte[0]);
            ExportKeyPromise promise = new ExportKeyPromise();
            int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
            if (error == NO_ERROR) {
                return promise.getFuture().get();
@@ -805,6 +842,8 @@ public class KeyStore {
        } catch (ExecutionException | InterruptedException e) {
            Log.e(TAG, "ExportKey completed with exception", e);
            return null;
        } finally {
            mBinder.asBinder().unlinkToDeath(promise, 0);
        }
    }
    public ExportResult exportKey(String alias, int format, KeymasterBlob clientId,
@@ -813,7 +852,8 @@ public class KeyStore {
    }

    private class OperationPromise
    extends android.security.keystore.IKeystoreOperationResultCallback.Stub {
            extends android.security.keystore.IKeystoreOperationResultCallback.Stub
            implements IBinder.DeathRecipient {
        final private CompletableFuture<OperationResult> future = new CompletableFuture<OperationResult>();
        @Override
        public void onFinished(OperationResult operationResult) throws android.os.RemoteException {
@@ -822,14 +862,19 @@ public class KeyStore {
        public final CompletableFuture<OperationResult> getFuture() {
            return future;
        }
        @Override
        public void binderDied() {
            future.completeExceptionally(new RemoteException("Keystore died"));
        }
    };

    public OperationResult begin(String alias, int purpose, boolean pruneable,
            KeymasterArguments args, byte[] entropy, int uid) {
        OperationPromise promise = new OperationPromise();
        try {
            mBinder.asBinder().linkToDeath(promise, 0);
            args = args != null ? args : new KeymasterArguments();
            entropy = entropy != null ? entropy : new byte[0];
            OperationPromise promise = new OperationPromise();
            int errorCode =  mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
                                           entropy, uid);
            if (errorCode == NO_ERROR) {
@@ -843,6 +888,8 @@ public class KeyStore {
        } catch (ExecutionException | InterruptedException e) {
            Log.e(TAG, "Begin completed with exception", e);
            return null;
        } finally {
            mBinder.asBinder().unlinkToDeath(promise, 0);
        }
    }

@@ -854,10 +901,11 @@ public class KeyStore {
    }

    public OperationResult update(IBinder token, KeymasterArguments arguments, byte[] input) {
        OperationPromise promise = new OperationPromise();
        try {
            mBinder.asBinder().linkToDeath(promise, 0);
            arguments = arguments != null ? arguments : new KeymasterArguments();
            input = input != null ? input : new byte[0];
            OperationPromise promise = new OperationPromise();
            int errorCode =  mBinder.update(promise, token, arguments, input);
            if (errorCode == NO_ERROR) {
                return promise.getFuture().get();
@@ -870,16 +918,19 @@ public class KeyStore {
        } catch (ExecutionException | InterruptedException e) {
            Log.e(TAG, "Update completed with exception", e);
            return null;
        } finally {
            mBinder.asBinder().unlinkToDeath(promise, 0);
        }
    }

    public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature,
            byte[] entropy) {
        OperationPromise promise = new OperationPromise();
        try {
            mBinder.asBinder().linkToDeath(promise, 0);
            arguments = arguments != null ? arguments : new KeymasterArguments();
            entropy = entropy != null ? entropy : new byte[0];
            signature = signature != null ? signature : new byte[0];
            OperationPromise promise = new OperationPromise();
            int errorCode = mBinder.finish(promise, token, arguments, signature, entropy);
            if (errorCode == NO_ERROR) {
                return promise.getFuture().get();
@@ -892,6 +943,8 @@ public class KeyStore {
        } catch (ExecutionException | InterruptedException e) {
            Log.e(TAG, "Finish completed with exception", e);
            return null;
        } finally {
            mBinder.asBinder().unlinkToDeath(promise, 0);
        }
    }

@@ -900,7 +953,8 @@ public class KeyStore {
    }

    private class KeystoreResultPromise
    extends android.security.keystore.IKeystoreResponseCallback.Stub {
            extends android.security.keystore.IKeystoreResponseCallback.Stub
            implements IBinder.DeathRecipient {
        final private CompletableFuture<KeystoreResponse> future = new CompletableFuture<KeystoreResponse>();
        @Override
        public void onFinished(KeystoreResponse keystoreResponse) throws android.os.RemoteException {
@@ -909,11 +963,16 @@ public class KeyStore {
        public final CompletableFuture<KeystoreResponse> getFuture() {
            return future;
        }
        @Override
        public void binderDied() {
            future.completeExceptionally(new RemoteException("Keystore died"));
        }
    };

    public int abort(IBinder token) {
        try {
        KeystoreResultPromise promise = new KeystoreResultPromise();
        try {
            mBinder.asBinder().linkToDeath(promise, 0);
            int errorCode = mBinder.abort(promise, token);
            if (errorCode == NO_ERROR) {
                return promise.getFuture().get().getErrorCode();
@@ -926,6 +985,8 @@ public class KeyStore {
        } catch (ExecutionException | InterruptedException e) {
            Log.e(TAG, "Abort completed with exception", e);
            return SYSTEM_ERROR;
        } finally {
            mBinder.asBinder().unlinkToDeath(promise, 0);
        }
    }

@@ -1035,7 +1096,8 @@ public class KeyStore {
    }

    private class CertificateChainPromise
    extends android.security.keystore.IKeystoreCertificateChainCallback.Stub {
            extends android.security.keystore.IKeystoreCertificateChainCallback.Stub
            implements IBinder.DeathRecipient {
        final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>();
        @Override
        public void onFinished(KeystoreResponse keystoreResponse,
@@ -1045,19 +1107,24 @@ public class KeyStore {
        public final CompletableFuture<KeyAttestationCallbackResult> getFuture() {
            return future;
        }
        @Override
        public void binderDied() {
            future.completeExceptionally(new RemoteException("Keystore died"));
        }
    };


    public int attestKey(
            String alias, KeymasterArguments params, KeymasterCertificateChain outChain) {
        CertificateChainPromise promise = new CertificateChainPromise();
        try {
            mBinder.asBinder().linkToDeath(promise, 0);
            if (params == null) {
                params = new KeymasterArguments();
            }
            if (outChain == null) {
                outChain = new KeymasterCertificateChain();
            }
            CertificateChainPromise promise = new CertificateChainPromise();
            int error = mBinder.attestKey(promise, alias, params);
            if (error != NO_ERROR) return error;
            KeyAttestationCallbackResult result = promise.getFuture().get();
@@ -1072,18 +1139,21 @@ public class KeyStore {
        } catch (ExecutionException | InterruptedException e) {
            Log.e(TAG, "AttestKey completed with exception", e);
            return SYSTEM_ERROR;
        } finally {
            mBinder.asBinder().unlinkToDeath(promise, 0);
        }
    }

    public int attestDeviceIds(KeymasterArguments params, KeymasterCertificateChain outChain) {
        CertificateChainPromise promise = new CertificateChainPromise();
        try {
            mBinder.asBinder().linkToDeath(promise, 0);
            if (params == null) {
                params = new KeymasterArguments();
            }
            if (outChain == null) {
                outChain = new KeymasterCertificateChain();
            }
            CertificateChainPromise promise = new CertificateChainPromise();
            int error = mBinder.attestDeviceIds(promise, params);
            if (error != NO_ERROR) return error;
            KeyAttestationCallbackResult result = promise.getFuture().get();
@@ -1098,6 +1168,8 @@ public class KeyStore {
        } catch (ExecutionException | InterruptedException e) {
            Log.e(TAG, "AttestDevicdeIds completed with exception", e);
            return SYSTEM_ERROR;
        } finally {
            mBinder.asBinder().unlinkToDeath(promise, 0);
        }
    }