summaryrefslogtreecommitdiff
path: root/core/java/android/security/ConfirmationDialog.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/java/android/security/ConfirmationDialog.java')
-rw-r--r--core/java/android/security/ConfirmationDialog.java332
1 files changed, 0 insertions, 332 deletions
diff --git a/core/java/android/security/ConfirmationDialog.java b/core/java/android/security/ConfirmationDialog.java
deleted file mode 100644
index 1697106c3782..000000000000
--- a/core/java/android/security/ConfirmationDialog.java
+++ /dev/null
@@ -1,332 +0,0 @@
-/*
- * Copyright 2018 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.content.ContentResolver;
-import android.content.Context;
-import android.provider.Settings;
-import android.provider.Settings.SettingNotFoundException;
-import android.text.TextUtils;
-import android.util.Log;
-
-import java.util.Locale;
-import java.util.concurrent.Executor;
-
-/**
- * Class used for displaying confirmation prompts.
- *
- * <p>Confirmation prompts are prompts shown to the user to confirm a given text and are
- * implemented in a way that a positive response indicates with high confidence that the user has
- * seen the given text, even if the Android framework (including the kernel) was
- * compromised. Implementing confirmation prompts with these guarantees requires dedicated
- * hardware-support and may not always be available.
- *
- * <p>Confirmation prompts are typically used with an external entitity - the <i>Relying Party</i> -
- * in the following way. The setup steps are as follows:
- * <ul>
- * <li> Before first use, the application generates a key-pair with the
- * {@link android.security.keystore.KeyGenParameterSpec.Builder#setUserConfirmationRequired
- * CONFIRMATION tag} set. Device attestation,
- * e.g. {@link java.security.KeyStore#getCertificateChain getCertificateChain()}, is used to
- * generate a certificate chain that includes the public key (<code>Kpub</code> in the following)
- * of the newly generated key.
- * <li> The application sends <code>Kpub</code> and the certificate chain resulting from device
- * attestation to the <i>Relying Party</i>.
- * <li> The <i>Relying Party</i> validates the certificate chain which involves checking the root
- * certificate is what is expected (e.g. a certificate from Google), each certificate signs the
- * next one in the chain, ending with <code>Kpub</code>, and that the attestation certificate
- * asserts that <code>Kpub</code> has the
- * {@link android.security.keystore.KeyGenParameterSpec.Builder#setUserConfirmationRequired
- * CONFIRMATION tag} set.
- * Additionally the relying party stores <code>Kpub</code> and associates it with the device
- * it was received from.
- * </ul>
- *
- * <p>The <i>Relying Party</i> is typically an external device (for example connected via
- * Bluetooth) or application server.
- *
- * <p>Before executing a transaction which requires a high assurance of user content, the
- * application does the following:
- * <ul>
- * <li> The application gets a cryptographic nonce from the <i>Relying Party</i> and passes this as
- * the <code>extraData</code> (via the Builder helper class) to the
- * {@link #presentPrompt presentPrompt()} method. The <i>Relying Party</i> stores the nonce locally
- * since it'll use it in a later step.
- * <li> If the user approves the prompt a <i>Confirmation Response</i> is returned in the
- * {@link ConfirmationCallback#onConfirmedByUser onConfirmedByUser(byte[])} callback as the
- * <code>dataThatWasConfirmed</code> parameter. This blob contains the text that was shown to the
- * user, the <code>extraData</code> parameter, and possibly other data.
- * <li> The application signs the <i>Confirmation Response</i> with the previously created key and
- * sends the blob and the signature to the <i>Relying Party</i>.
- * <li> The <i>Relying Party</i> checks that the signature was made with <code>Kpub</code> and then
- * extracts <code>promptText</code> matches what is expected and <code>extraData</code> matches the
- * previously created nonce. If all checks passes, the transaction is executed.
- * </ul>
- *
- * <p>A common way of implementing the "<code>promptText</code> is what is expected" check in the
- * last bullet, is to have the <i>Relying Party</i> generate <code>promptText</code> and store it
- * along the nonce in the <code>extraData</code> blob.
- */
-public class ConfirmationDialog {
- private static final String TAG = "ConfirmationDialog";
-
- private CharSequence mPromptText;
- private byte[] mExtraData;
- private ConfirmationCallback mCallback;
- private Executor mExecutor;
- private Context mContext;
-
- private final KeyStore mKeyStore = KeyStore.getInstance();
-
- private void doCallback(int responseCode, byte[] dataThatWasConfirmed,
- ConfirmationCallback callback) {
- switch (responseCode) {
- case KeyStore.CONFIRMATIONUI_OK:
- callback.onConfirmedByUser(dataThatWasConfirmed);
- break;
-
- case KeyStore.CONFIRMATIONUI_CANCELED:
- callback.onDismissedByUser();
- break;
-
- case KeyStore.CONFIRMATIONUI_ABORTED:
- callback.onDismissedByApplication();
- break;
-
- case KeyStore.CONFIRMATIONUI_SYSTEM_ERROR:
- callback.onError(new Exception("System error returned by ConfirmationUI."));
- break;
-
- default:
- callback.onError(new Exception("Unexpected responseCode=" + responseCode
- + " from onConfirmtionPromptCompleted() callback."));
- break;
- }
- }
-
- private final android.os.IBinder mCallbackBinder =
- new android.security.IConfirmationPromptCallback.Stub() {
- @Override
- public void onConfirmationPromptCompleted(
- int responseCode, final byte[] dataThatWasConfirmed)
- throws android.os.RemoteException {
- if (mCallback != null) {
- ConfirmationCallback callback = mCallback;
- Executor executor = mExecutor;
- mCallback = null;
- mExecutor = null;
- if (executor == null) {
- doCallback(responseCode, dataThatWasConfirmed, callback);
- } else {
- executor.execute(new Runnable() {
- @Override
- public void run() {
- doCallback(responseCode, dataThatWasConfirmed, callback);
- }
- });
- }
- }
- }
- };
-
- /**
- * A builder that collects arguments, to be shown on the system-provided confirmation dialog.
- */
- public static class Builder {
-
- private CharSequence mPromptText;
- private byte[] mExtraData;
-
- /**
- * Creates a builder for the confirmation dialog.
- */
- public Builder() {
- }
-
- /**
- * Sets the prompt text for the dialog.
- *
- * @param promptText the text to present in the prompt.
- * @return the builder.
- */
- public Builder setPromptText(CharSequence promptText) {
- mPromptText = promptText;
- return this;
- }
-
- /**
- * Sets the extra data for the dialog.
- *
- * @param extraData data to include in the response data.
- * @return the builder.
- */
- public Builder setExtraData(byte[] extraData) {
- mExtraData = extraData;
- return this;
- }
-
- /**
- * Creates a {@link ConfirmationDialog} with the arguments supplied to this builder.
- *
- * @param context the application context
- * @return a {@link ConfirmationDialog}
- * @throws IllegalArgumentException if any of the required fields are not set.
- */
- public ConfirmationDialog build(Context context) {
- if (TextUtils.isEmpty(mPromptText)) {
- throw new IllegalArgumentException("prompt text must be set and non-empty");
- }
- if (mExtraData == null) {
- throw new IllegalArgumentException("extraData must be set");
- }
- return new ConfirmationDialog(context, mPromptText, mExtraData);
- }
- }
-
- private ConfirmationDialog(Context context, CharSequence promptText, byte[] extraData) {
- mContext = context;
- mPromptText = promptText;
- mExtraData = extraData;
- }
-
- private static final int UI_OPTION_ACCESSIBILITY_INVERTED_FLAG = 1 << 0;
- private static final int UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG = 1 << 1;
-
- private int getUiOptionsAsFlags() {
- int uiOptionsAsFlags = 0;
- try {
- ContentResolver contentResolver = mContext.getContentResolver();
- int inversionEnabled = Settings.Secure.getInt(contentResolver,
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
- if (inversionEnabled == 1) {
- uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_INVERTED_FLAG;
- }
- float fontScale = Settings.System.getFloat(contentResolver,
- Settings.System.FONT_SCALE);
- if (fontScale > 1.0) {
- uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG;
- }
- } catch (SettingNotFoundException e) {
- Log.w(TAG, "Unexpected SettingNotFoundException");
- }
- return uiOptionsAsFlags;
- }
-
- private boolean isAccessibilityServiceRunning() {
- boolean serviceRunning = false;
- try {
- ContentResolver contentResolver = mContext.getContentResolver();
- int a11yEnabled = Settings.Secure.getInt(contentResolver,
- Settings.Secure.ACCESSIBILITY_ENABLED);
- if (a11yEnabled == 1) {
- serviceRunning = true;
- }
- } catch (SettingNotFoundException e) {
- Log.w(TAG, "Unexpected SettingNotFoundException");
- e.printStackTrace();
- }
- return serviceRunning;
- }
-
- /**
- * Requests a confirmation prompt to be presented to the user.
- *
- * When the prompt is no longer being presented, one of the methods in
- * {@link ConfirmationCallback} is called on the supplied callback object.
- *
- * Confirmation dialogs may not be available when accessibility services are running so this
- * may fail with a {@link ConfirmationNotAvailableException} exception even if
- * {@link #isSupported} returns {@code true}.
- *
- * @param executor the executor identifying the thread that will receive the callback.
- * @param callback the callback to use when the dialog is done showing.
- * @throws IllegalArgumentException if the prompt text is too long or malfomed.
- * @throws ConfirmationAlreadyPresentingException if another prompt is being presented.
- * @throws ConfirmationNotAvailableException if confirmation prompts are not supported.
- */
- public void presentPrompt(@NonNull Executor executor, @NonNull ConfirmationCallback callback)
- throws ConfirmationAlreadyPresentingException,
- ConfirmationNotAvailableException {
- if (mCallback != null) {
- throw new ConfirmationAlreadyPresentingException();
- }
- if (isAccessibilityServiceRunning()) {
- throw new ConfirmationNotAvailableException();
- }
- mCallback = callback;
- mExecutor = executor;
-
- int uiOptionsAsFlags = getUiOptionsAsFlags();
- String locale = Locale.getDefault().toLanguageTag();
- int responseCode = mKeyStore.presentConfirmationPrompt(
- mCallbackBinder, mPromptText.toString(), mExtraData, locale, uiOptionsAsFlags);
- switch (responseCode) {
- case KeyStore.CONFIRMATIONUI_OK:
- return;
-
- case KeyStore.CONFIRMATIONUI_OPERATION_PENDING:
- throw new ConfirmationAlreadyPresentingException();
-
- case KeyStore.CONFIRMATIONUI_UNIMPLEMENTED:
- throw new ConfirmationNotAvailableException();
-
- case KeyStore.CONFIRMATIONUI_UIERROR:
- throw new IllegalArgumentException();
-
- default:
- // Unexpected error code.
- Log.w(TAG,
- "Unexpected responseCode=" + responseCode
- + " from presentConfirmationPrompt() call.");
- throw new IllegalArgumentException();
- }
- }
-
- /**
- * Cancels a prompt currently being displayed.
- *
- * On success, the
- * {@link ConfirmationCallback#onDismissedByApplication onDismissedByApplication()} method on
- * the supplied callback object will be called asynchronously.
- *
- * @throws IllegalStateException if no prompt is currently being presented.
- */
- public void cancelPrompt() {
- int responseCode = mKeyStore.cancelConfirmationPrompt(mCallbackBinder);
- if (responseCode == KeyStore.CONFIRMATIONUI_OK) {
- return;
- } else if (responseCode == KeyStore.CONFIRMATIONUI_OPERATION_PENDING) {
- throw new IllegalStateException();
- } else {
- // Unexpected error code.
- Log.w(TAG,
- "Unexpected responseCode=" + responseCode
- + " from cancelConfirmationPrompt() call.");
- throw new IllegalStateException();
- }
- }
-
- /**
- * Checks if the device supports confirmation prompts.
- *
- * @return true if confirmation prompts are supported by the device.
- */
- public static boolean isSupported() {
- return KeyStore.getInstance().isConfirmationPromptSupported();
- }
-}