/* * Copyright (C) 2020 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.security; import android.annotation.NonNull; import android.hardware.security.keymint.KeyParameter; import android.os.Binder; import android.os.RemoteException; import android.os.ServiceSpecificException; import android.os.StrictMode; import android.security.keymaster.KeymasterDefs; import android.system.keystore2.IKeystoreOperation; import android.system.keystore2.ResponseCode; import android.util.Log; /** * @hide */ public class KeyStoreOperation { static final String TAG = "KeyStoreOperation"; private final IKeystoreOperation mOperation; private final Long mChallenge; private final KeyParameter[] mParameters; public KeyStoreOperation( @NonNull IKeystoreOperation operation, Long challenge, KeyParameter[] parameters ) { Binder.allowBlocking(operation.asBinder()); this.mOperation = operation; this.mChallenge = challenge; this.mParameters = parameters; } /** * Gets the challenge associated with this operation. * @return null if the operation does not required authorization. A 64bit operation * challenge otherwise. */ public Long getChallenge() { return mChallenge; } /** * Gets the parameters associated with this operation. * @return */ public KeyParameter[] getParameters() { return mParameters; } private R handleExceptions(@NonNull CheckedRemoteRequest request) throws KeyStoreException { try { return request.execute(); } catch (ServiceSpecificException e) { switch(e.errorCode) { case ResponseCode.OPERATION_BUSY: { throw new IllegalThreadStateException( "Cannot update the same operation concurrently." ); } default: throw KeyStore2.getKeyStoreException(e.errorCode, e.getMessage()); } } catch (RemoteException e) { // Log exception and report invalid operation handle. // This should prompt the caller drop the reference to this operation and retry. Log.e( TAG, "Remote exception while advancing a KeyStoreOperation.", e ); throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_OPERATION_HANDLE, "", e.getMessage()); } } /** * Updates the Keystore operation represented by this object with more associated data. * @see IKeystoreOperation#updateAad(byte[]) for more details. * @param input * @throws KeyStoreException */ public void updateAad(@NonNull byte[] input) throws KeyStoreException { StrictMode.noteSlowCall("updateAad"); handleExceptions(() -> { mOperation.updateAad(input); return 0; }); } /** * Updates the Keystore operation represented by this object. * @see IKeystoreOperation#update(byte[]) for more details. * @param input * @return * @throws KeyStoreException * @hide */ public byte[] update(@NonNull byte[] input) throws KeyStoreException { StrictMode.noteSlowCall("update"); return handleExceptions(() -> mOperation.update(input)); } /** * Finalizes the Keystore operation represented by this object. * @see IKeystoreOperation#finish(byte[], byte[]) for more details. * @param input * @param signature * @return * @throws KeyStoreException * @hide */ public byte[] finish(byte[] input, byte[] signature) throws KeyStoreException { StrictMode.noteSlowCall("finish"); return handleExceptions(() -> mOperation.finish(input, signature)); } /** * Aborts the Keystore operation represented by this object. * @see IKeystoreOperation#abort() for more details. * @throws KeyStoreException * @hide */ public void abort() throws KeyStoreException { StrictMode.noteSlowCall("abort"); handleExceptions(() -> { mOperation.abort(); return 0; }); } }