Merge changes from topic "rename_qs_theme" into sc-dev
* changes:
Rename qs_theme
Rename SysUI base theme
diff --git a/Android.bp b/Android.bp
index 7b30056..955cfab 100644
--- a/Android.bp
+++ b/Android.bp
@@ -150,7 +150,6 @@
":incidentcompanion_aidl",
":inputconstants_aidl",
":installd_aidl",
- ":keystore_aidl",
":libaudioclient_aidl",
":libbinder_aidl",
":libbluetooth-binder-aidl",
diff --git a/config/hiddenapi-unsupported.txt b/config/hiddenapi-unsupported.txt
index 48aa8b2..4281b0d 100644
--- a/config/hiddenapi-unsupported.txt
+++ b/config/hiddenapi-unsupported.txt
@@ -208,7 +208,6 @@
Landroid/os/storage/IStorageManager$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
Landroid/os/storage/IStorageManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/os/storage/IStorageManager;
Landroid/security/IKeyChainService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/IKeyChainService;
-Landroid/security/keystore/IKeystoreService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/security/keystore/IKeystoreService;
Landroid/service/dreams/IDreamManager$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/dreams/IDreamManager;
Landroid/service/notification/INotificationListener$Stub;-><init>()V
Landroid/service/persistentdata/IPersistentDataBlockService$Stub;->asInterface(Landroid/os/IBinder;)Landroid/service/persistentdata/IPersistentDataBlockService;
diff --git a/core/java/android/hardware/biometrics/BiometricTestSession.java b/core/java/android/hardware/biometrics/BiometricTestSession.java
index ff1a17e..41672b7 100644
--- a/core/java/android/hardware/biometrics/BiometricTestSession.java
+++ b/core/java/android/hardware/biometrics/BiometricTestSession.java
@@ -38,7 +38,7 @@
*/
@TestApi
public class BiometricTestSession implements AutoCloseable {
- private static final String TAG = "BiometricTestSession";
+ private static final String BASE_TAG = "BiometricTestSession";
/**
* @hide
@@ -66,12 +66,12 @@
private final ITestSessionCallback mCallback = new ITestSessionCallback.Stub() {
@Override
public void onCleanupStarted(int userId) {
- Log.d(TAG, "onCleanupStarted, sensor: " + mSensorId + ", userId: " + userId);
+ Log.d(getTag(), "onCleanupStarted, sensor: " + mSensorId + ", userId: " + userId);
}
@Override
public void onCleanupFinished(int userId) {
- Log.d(TAG, "onCleanupFinished, sensor: " + mSensorId
+ Log.d(getTag(), "onCleanupFinished, sensor: " + mSensorId
+ ", userId: " + userId
+ ", remaining users: " + mUsersCleaningUp.size());
mUsersCleaningUp.remove(userId);
@@ -107,7 +107,7 @@
@RequiresPermission(TEST_BIOMETRIC)
private void setTestHalEnabled(boolean enabled) {
try {
- Log.w(TAG, "setTestHalEnabled, sensor: " + mSensorId + " enabled: " + enabled);
+ Log.w(getTag(), "setTestHalEnabled, sensor: " + mSensorId + " enabled: " + enabled);
mTestSession.setTestHalEnabled(enabled);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
@@ -217,7 +217,7 @@
public void cleanupInternalState(int userId) {
try {
if (mUsersCleaningUp.contains(userId)) {
- Log.w(TAG, "Cleanup already in progress for user: " + userId);
+ Log.w(getTag(), "Cleanup already in progress for user: " + userId);
}
mUsersCleaningUp.add(userId);
@@ -230,6 +230,7 @@
@Override
@RequiresPermission(TEST_BIOMETRIC)
public void close() {
+ Log.d(getTag(), "Close, mTestedUsers size; " + mTestedUsers.size());
// Cleanup can be performed using the test HAL, since it always responds to enumerate with
// zero enrollments.
if (!mTestedUsers.isEmpty()) {
@@ -239,15 +240,19 @@
}
try {
- Log.d(TAG, "Awaiting latch...");
- mCloseLatch.await(10, TimeUnit.SECONDS);
- Log.d(TAG, "Finished awaiting");
+ Log.d(getTag(), "Awaiting latch...");
+ mCloseLatch.await(3, TimeUnit.SECONDS);
+ Log.d(getTag(), "Finished awaiting");
} catch (InterruptedException e) {
- Log.e(TAG, "Latch interrupted", e);
+ Log.e(getTag(), "Latch interrupted", e);
}
}
// Disable the test HAL after the sensor becomes idle.
setTestHalEnabled(false);
}
+
+ private String getTag() {
+ return BASE_TAG + "_" + mSensorId;
+ }
}
diff --git a/core/java/android/security/ConfirmationPrompt.java b/core/java/android/security/ConfirmationPrompt.java
index 2329037..d8c44ad 100644
--- a/core/java/android/security/ConfirmationPrompt.java
+++ b/core/java/android/security/ConfirmationPrompt.java
@@ -21,7 +21,6 @@
import android.content.Context;
import android.provider.Settings;
import android.provider.Settings.SettingNotFoundException;
-import android.security.keystore.AndroidKeyStoreProvider;
import android.text.TextUtils;
import android.util.Log;
@@ -106,32 +105,6 @@
private void doCallback(int responseCode, byte[] dataThatWasConfirmed,
ConfirmationCallback callback) {
switch (responseCode) {
- case KeyStore.CONFIRMATIONUI_OK:
- callback.onConfirmed(dataThatWasConfirmed);
- break;
-
- case KeyStore.CONFIRMATIONUI_CANCELED:
- callback.onDismissed();
- break;
-
- case KeyStore.CONFIRMATIONUI_ABORTED:
- callback.onCanceled();
- 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 void doCallback2(int responseCode, byte[] dataThatWasConfirmed,
- ConfirmationCallback callback) {
- switch (responseCode) {
case AndroidProtectedConfirmation.ERROR_OK:
callback.onConfirmed(dataThatWasConfirmed);
break;
@@ -155,31 +128,6 @@
}
}
- 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);
- }
- });
- }
- }
- }
- };
-
private final android.security.apc.IConfirmationCallback mConfirmationCallback =
new android.security.apc.IConfirmationCallback.Stub() {
@Override
@@ -191,11 +139,11 @@
mCallback = null;
mExecutor = null;
if (executor == null) {
- doCallback2(result, dataThatWasConfirmed, callback);
+ doCallback(result, dataThatWasConfirmed, callback);
} else {
executor.execute(new Runnable() {
@Override public void run() {
- doCallback2(result, dataThatWasConfirmed, callback);
+ doCallback(result, dataThatWasConfirmed, callback);
}
});
}
@@ -266,29 +214,7 @@
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() {
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- return getUiOptionsAsFlags2();
- }
- int uiOptionsAsFlags = 0;
- ContentResolver contentResolver = mContext.getContentResolver();
- int inversionEnabled = Settings.Secure.getInt(contentResolver,
- Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED, 0);
- if (inversionEnabled == 1) {
- uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_INVERTED_FLAG;
- }
- float fontScale = Settings.System.getFloat(contentResolver,
- Settings.System.FONT_SCALE, (float) 1.0);
- if (fontScale > 1.0) {
- uiOptionsAsFlags |= UI_OPTION_ACCESSIBILITY_MAGNIFIED_FLAG;
- }
- return uiOptionsAsFlags;
- }
-
- private int getUiOptionsAsFlags2() {
int uiOptionsAsFlags = 0;
ContentResolver contentResolver = mContext.getContentResolver();
int inversionEnabled = Settings.Secure.getInt(contentResolver,
@@ -349,52 +275,26 @@
mExecutor = executor;
String locale = Locale.getDefault().toLanguageTag();
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- int uiOptionsAsFlags = getUiOptionsAsFlags2();
- int responseCode = getService().presentConfirmationPrompt(
- mConfirmationCallback, mPromptText.toString(), mExtraData, locale,
- uiOptionsAsFlags);
- switch (responseCode) {
- case AndroidProtectedConfirmation.ERROR_OK:
- return;
+ int uiOptionsAsFlags = getUiOptionsAsFlags();
+ int responseCode = getService().presentConfirmationPrompt(
+ mConfirmationCallback, mPromptText.toString(), mExtraData, locale,
+ uiOptionsAsFlags);
+ switch (responseCode) {
+ case AndroidProtectedConfirmation.ERROR_OK:
+ return;
- case AndroidProtectedConfirmation.ERROR_OPERATION_PENDING:
- throw new ConfirmationAlreadyPresentingException();
+ case AndroidProtectedConfirmation.ERROR_OPERATION_PENDING:
+ throw new ConfirmationAlreadyPresentingException();
- case AndroidProtectedConfirmation.ERROR_UNIMPLEMENTED:
- throw new ConfirmationNotAvailableException();
+ case AndroidProtectedConfirmation.ERROR_UNIMPLEMENTED:
+ throw new ConfirmationNotAvailableException();
- default:
- // Unexpected error code.
- Log.w(TAG,
- "Unexpected responseCode=" + responseCode
- + " from presentConfirmationPrompt() call.");
- throw new IllegalArgumentException();
- }
- } else {
- int uiOptionsAsFlags = getUiOptionsAsFlags();
- 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();
- }
+ default:
+ // Unexpected error code.
+ Log.w(TAG,
+ "Unexpected responseCode=" + responseCode
+ + " from presentConfirmationPrompt() call.");
+ throw new IllegalArgumentException();
}
}
@@ -408,33 +308,18 @@
* @throws IllegalStateException if no prompt is currently being presented.
*/
public void cancelPrompt() {
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- int responseCode =
- getService().cancelConfirmationPrompt(mConfirmationCallback);
- if (responseCode == AndroidProtectedConfirmation.ERROR_OK) {
- return;
- } else if (responseCode == AndroidProtectedConfirmation.ERROR_OPERATION_PENDING) {
- throw new IllegalStateException();
- } else {
- // Unexpected error code.
- Log.w(TAG,
- "Unexpected responseCode=" + responseCode
- + " from cancelConfirmationPrompt() call.");
- throw new IllegalStateException();
- }
+ int responseCode =
+ getService().cancelConfirmationPrompt(mConfirmationCallback);
+ if (responseCode == AndroidProtectedConfirmation.ERROR_OK) {
+ return;
+ } else if (responseCode == AndroidProtectedConfirmation.ERROR_OPERATION_PENDING) {
+ throw new IllegalStateException();
} else {
- 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();
- }
+ // Unexpected error code.
+ Log.w(TAG,
+ "Unexpected responseCode=" + responseCode
+ + " from cancelConfirmationPrompt() call.");
+ throw new IllegalStateException();
}
}
@@ -448,9 +333,6 @@
if (isAccessibilityServiceRunning(context)) {
return false;
}
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- return new AndroidProtectedConfirmation().isConfirmationPromptSupported();
- }
- return KeyStore.getInstance().isConfirmationPromptSupported();
+ return new AndroidProtectedConfirmation().isConfirmationPromptSupported();
}
}
diff --git a/core/java/android/security/keymaster/KeymasterCertificateChain.aidl b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
new file mode 100644
index 0000000..e01db7a
--- /dev/null
+++ b/core/java/android/security/keymaster/KeymasterCertificateChain.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2021 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.keymaster;
+
+parcelable KeymasterCertificateChain;
diff --git a/core/java/android/security/keystore/recovery/RecoveryController.java b/core/java/android/security/keystore/recovery/RecoveryController.java
index 6788353..ad9b796 100644
--- a/core/java/android/security/keystore/recovery/RecoveryController.java
+++ b/core/java/android/security/keystore/recovery/RecoveryController.java
@@ -712,18 +712,10 @@
*/
@NonNull Key getKeyFromGrant(@NonNull String grantAlias)
throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- if (grantAlias.startsWith(APPLICATION_KEY_GRANT_PREFIX)) {
- return AndroidKeyStoreProvider
- .loadAndroidKeyStoreSecretKeyFromKeystore(
- KeyStore2.getInstance(),
- getGrantDescriptor(grantAlias));
- }
- // TODO(b/171305545): remove KeyStore1 logic.
- return android.security.keystore.AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(
- mKeyStore,
- grantAlias,
- KeyStore.UID_SELF);
-
+ return AndroidKeyStoreProvider
+ .loadAndroidKeyStoreSecretKeyFromKeystore(
+ KeyStore2.getInstance(),
+ getGrantDescriptor(grantAlias));
}
private static final String APPLICATION_KEY_GRANT_PREFIX = "recoverable_key:";
diff --git a/core/java/android/widget/EdgeEffect.java b/core/java/android/widget/EdgeEffect.java
index 1951194..ae426d2 100644
--- a/core/java/android/widget/EdgeEffect.java
+++ b/core/java/android/widget/EdgeEffect.java
@@ -626,20 +626,31 @@
// assume rotations of increments of 90 degrees
float x = mTmpPoints[10] - mTmpPoints[8];
float width = right - left;
- float vecX = dampStretchVector(Math.max(-1f, Math.min(1f, x / width)));
+ float vecX = 0f;
+ if (width > 0) {
+ vecX = dampStretchVector(Math.max(-1f, Math.min(1f, x / width)));
+ }
+
float y = mTmpPoints[11] - mTmpPoints[9];
float height = bottom - top;
- float vecY = dampStretchVector(Math.max(-1f, Math.min(1f, y / height)));
- renderNode.stretch(
- left,
- top,
- right,
- bottom,
- vecX,
- vecY,
- mWidth,
- mHeight
- );
+ float vecY = 0f;
+ if (height > 0) {
+ vecY = dampStretchVector(Math.max(-1f, Math.min(1f, y / height)));
+ }
+
+ boolean hasStretchVectors = Float.compare(vecX, 0) != 0 || Float.compare(vecY, 0) != 0;
+ if (right > left && bottom > top && mWidth > 0 && mHeight > 0 && hasStretchVectors) {
+ renderNode.stretch(
+ left,
+ top,
+ right,
+ bottom,
+ vecX,
+ vecY,
+ mWidth,
+ mHeight
+ );
+ }
} else {
// This is TYPE_STRETCH and drawing into a Canvas that isn't a Recording Canvas,
// so no effect can be shown. Just end the effect.
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index f907e25..361b836 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -41,6 +41,7 @@
import android.os.ZygoteProcess;
import android.os.storage.StorageManager;
import android.provider.DeviceConfig;
+import android.security.keystore2.AndroidKeyStoreProvider;
import android.system.ErrnoException;
import android.system.Os;
import android.system.OsConstants;
@@ -216,10 +217,8 @@
long startTime = SystemClock.uptimeMillis();
Trace.traceBegin(
Trace.TRACE_TAG_DALVIK, "Starting installation of AndroidKeyStoreProvider");
- // AndroidKeyStoreProvider.install() manipulates the list of JCA providers to insert
- // preferred providers. Note this is not done via security.properties as the JCA providers
- // are not on the classpath in the case of, for example, raw dalvikvm runtimes.
- android.security.keystore2.AndroidKeyStoreProvider.install();
+
+ AndroidKeyStoreProvider.install();
Log.i(TAG, "Installed AndroidKeyStoreProvider in "
+ (SystemClock.uptimeMillis() - startTime) + "ms.");
Trace.traceEnd(Trace.TRACE_TAG_DALVIK);
diff --git a/keystore/java/android/security/AndroidKeyStoreMaintenance.java b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
index 72cea0c..82639de 100644
--- a/keystore/java/android/security/AndroidKeyStoreMaintenance.java
+++ b/keystore/java/android/security/AndroidKeyStoreMaintenance.java
@@ -47,7 +47,6 @@
* @hide
*/
public static int onUserAdded(@NonNull int userId) {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
try {
getService().onUserAdded(userId);
return 0;
@@ -68,7 +67,6 @@
* @hide
*/
public static int onUserRemoved(int userId) {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
try {
getService().onUserRemoved(userId);
return 0;
@@ -91,7 +89,6 @@
* @hide
*/
public static int onUserPasswordChanged(int userId, @Nullable byte[] password) {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
try {
getService().onUserPasswordChanged(userId, password);
return 0;
@@ -109,7 +106,6 @@
* be cleared.
*/
public static int clearNamespace(@Domain int domain, long namespace) {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
try {
getService().clearNamespace(domain, namespace);
return 0;
@@ -144,7 +140,6 @@
* Informs Keystore 2.0 that an off body event was detected.
*/
public static void onDeviceOffBody() {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return;
try {
getService().onDeviceOffBody();
} catch (Exception e) {
diff --git a/keystore/java/android/security/Authorization.java b/keystore/java/android/security/Authorization.java
index 50a9082..bd72d45 100644
--- a/keystore/java/android/security/Authorization.java
+++ b/keystore/java/android/security/Authorization.java
@@ -48,7 +48,6 @@
* @return 0 if successful or {@code ResponseCode.SYSTEM_ERROR}.
*/
public static int addAuthToken(@NonNull HardwareAuthToken authToken) {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
try {
getService().addAuthToken(authToken);
return 0;
@@ -80,7 +79,6 @@
*/
public static int onLockScreenEvent(@NonNull boolean locked, @NonNull int userId,
@Nullable byte[] syntheticPassword) {
- if (!android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) return 0;
try {
if (locked) {
getService().onLockScreenEvent(LockScreenEvent.LOCK, userId, null);
diff --git a/keystore/java/android/security/Credentials.java b/keystore/java/android/security/Credentials.java
index ae9f8664..28c601b 100644
--- a/keystore/java/android/security/Credentials.java
+++ b/keystore/java/android/security/Credentials.java
@@ -208,78 +208,4 @@
pr.close();
}
}
-
- /**
- * Delete all types (private key, user certificate, CA certificate) for a
- * particular {@code alias}. All three can exist for any given alias.
- * Returns {@code true} if the alias no longer contains any types.
- */
- public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias) {
- return deleteAllTypesForAlias(keystore, alias, KeyStore.UID_SELF);
- }
-
- /**
- * Delete all types (private key, user certificate, CA certificate) for a
- * particular {@code alias}. All three can exist for any given alias.
- * Returns {@code true} if the alias no longer contains any types.
- */
- public static boolean deleteAllTypesForAlias(KeyStore keystore, String alias, int uid) {
- /*
- * Make sure every type is deleted. There can be all three types, so
- * don't use a conditional here.
- */
- return deleteUserKeyTypeForAlias(keystore, alias, uid)
- & deleteCertificateTypesForAlias(keystore, alias, uid);
- }
-
- /**
- * Delete certificate types (user certificate, CA certificate) for a
- * particular {@code alias}. Both can exist for any given alias.
- * Returns {@code true} if the alias no longer contains either type.
- */
- public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias) {
- return deleteCertificateTypesForAlias(keystore, alias, KeyStore.UID_SELF);
- }
-
- /**
- * Delete certificate types (user certificate, CA certificate) for a
- * particular {@code alias}. Both can exist for any given alias.
- * Returns {@code true} if the alias no longer contains either type.
- */
- public static boolean deleteCertificateTypesForAlias(KeyStore keystore, String alias, int uid) {
- /*
- * Make sure every certificate type is deleted. There can be two types,
- * so don't use a conditional here.
- */
- return keystore.delete(Credentials.USER_CERTIFICATE + alias, uid)
- & keystore.delete(Credentials.CA_CERTIFICATE + alias, uid);
- }
-
- /**
- * Delete user key for a particular {@code alias}.
- * Returns {@code true} if the entry no longer exists.
- */
- public static boolean deleteUserKeyTypeForAlias(KeyStore keystore, String alias) {
- return deleteUserKeyTypeForAlias(keystore, alias, KeyStore.UID_SELF);
- }
-
- /**
- * Delete user key for a particular {@code alias}.
- * Returns {@code true} if the entry no longer exists.
- */
- public static boolean deleteUserKeyTypeForAlias(KeyStore keystore, String alias, int uid) {
- int ret = keystore.delete2(Credentials.USER_PRIVATE_KEY + alias, uid);
- if (ret == KeyStore.KEY_NOT_FOUND) {
- return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
- }
- return ret == KeyStore.NO_ERROR;
- }
-
- /**
- * Delete legacy prefixed entry for a particular {@code alias}
- * Returns {@code true} if the entry no longer exists.
- */
- public static boolean deleteLegacyKeyForAlias(KeyStore keystore, String alias, int uid) {
- return keystore.delete(Credentials.USER_SECRET_KEY + alias, uid);
- }
}
diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java
index 7c80f70..02cdeef 100644
--- a/keystore/java/android/security/KeyChain.java
+++ b/keystore/java/android/security/KeyChain.java
@@ -42,7 +42,6 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
-import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.system.keystore2.Domain;
@@ -806,23 +805,13 @@
return null;
}
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- try {
- return android.security.keystore2.AndroidKeyStoreProvider
- .loadAndroidKeyStoreKeyPairFromKeystore(
- KeyStore2.getInstance(),
- getGrantDescriptor(keyId));
- } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
- throw new KeyChainException(e);
- }
- } else {
- try {
- return AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
- KeyStore.getInstance(), keyId, KeyStore.UID_SELF);
- } catch (RuntimeException | UnrecoverableKeyException
- | KeyPermanentlyInvalidatedException e) {
- throw new KeyChainException(e);
- }
+ try {
+ return android.security.keystore2.AndroidKeyStoreProvider
+ .loadAndroidKeyStoreKeyPairFromKeystore(
+ KeyStore2.getInstance(),
+ getGrantDescriptor(keyId));
+ } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
+ throw new KeyChainException(e);
}
}
diff --git a/keystore/java/android/security/KeyStore.java b/keystore/java/android/security/KeyStore.java
index b05149e..a954344 100644
--- a/keystore/java/android/security/KeyStore.java
+++ b/keystore/java/android/security/KeyStore.java
@@ -16,53 +16,11 @@
package android.security;
-import android.app.ActivityThread;
-import android.app.Application;
-import android.app.KeyguardManager;
import android.compat.annotation.UnsupportedAppUsage;
-import android.content.Context;
-import android.hardware.biometrics.BiometricManager;
-import android.os.Binder;
import android.os.Build;
-import android.os.IBinder;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
import android.os.UserHandle;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterBlob;
-import android.security.keymaster.KeymasterCertificateChain;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-import android.security.keystore.IKeystoreService;
-import android.security.keystore.KeyExpiredException;
-import android.security.keystore.KeyNotYetValidException;
-import android.security.keystore.KeyPermanentlyInvalidatedException;
-import android.security.keystore.KeyProperties;
-import android.security.keystore.KeystoreResponse;
-import android.security.keystore.UserNotAuthenticatedException;
import android.security.maintenance.UserState;
import android.system.keystore2.Domain;
-import android.util.Log;
-
-import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
-import com.android.internal.org.bouncycastle.asn1.pkcs.PrivateKeyInfo;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.security.InvalidKeyException;
-import java.util.ArrayList;
-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;
/**
* @hide This should not be made public in its present form because it
@@ -75,79 +33,10 @@
// ResponseCodes - see system/security/keystore/include/keystore/keystore.h
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static final int NO_ERROR = 1;
- public static final int LOCKED = 2;
- public static final int UNINITIALIZED = 3;
- public static final int SYSTEM_ERROR = 4;
- public static final int PROTOCOL_ERROR = 5;
- public static final int PERMISSION_DENIED = 6;
- public static final int KEY_NOT_FOUND = 7;
- public static final int VALUE_CORRUPTED = 8;
- public static final int UNDEFINED_ACTION = 9;
- public static final int WRONG_PASSWORD = 10;
- public static final int KEY_ALREADY_EXISTS = 16;
- public static final int CANNOT_ATTEST_IDS = -66;
- public static final int HARDWARE_TYPE_UNAVAILABLE = -68;
-
- /**
- * Per operation authentication is needed before this operation is valid.
- * This is returned from {@link #begin} when begin succeeds but the operation uses
- * per-operation authentication and must authenticate before calling {@link #update} or
- * {@link #finish}.
- */
- public static final int OP_AUTH_NEEDED = 15;
-
- // Used when a user changes their pin, invalidating old auth bound keys.
- public static final int KEY_PERMANENTLY_INVALIDATED = 17;
// Used for UID field to indicate the calling UID.
public static final int UID_SELF = -1;
- // Flags for "put" "import" and "generate"
- public static final int FLAG_NONE = 0;
-
- /**
- * Indicates that this key (or key pair) must be encrypted at rest. This will protect the key
- * (or key pair) with the secure lock screen credential (e.g., password, PIN, or pattern).
- *
- * <p>Note that this requires that the secure lock screen (e.g., password, PIN, pattern) is set
- * up, otherwise key (or key pair) generation or import will fail. Moreover, this key (or key
- * pair) will be deleted when the secure lock screen is disabled or reset (e.g., by the user or
- * a Device Administrator). Finally, this key (or key pair) cannot be used until the user
- * unlocks the secure lock screen after boot.
- *
- * @see KeyguardManager#isDeviceSecure()
- */
- public static final int FLAG_ENCRYPTED = 1;
-
- /**
- * Select Software keymaster device, which as of this writing is the lowest security
- * level available on an android device. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
- * A TEE based keymaster implementation is implied.
- *
- * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
- * For historical reasons this corresponds to the KEYSTORE_FLAG_FALLBACK flag.
- */
- public static final int FLAG_SOFTWARE = 1 << 1;
-
- /**
- * A private flag that's only available to system server to indicate that this key is part of
- * device encryption flow so it receives special treatment from keystore. For example this key
- * will not be super encrypted, and it will be stored separately under an unique UID instead
- * of the caller UID i.e. SYSTEM.
- *
- * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
- */
- public static final int FLAG_CRITICAL_TO_DEVICE_ENCRYPTION = 1 << 3;
-
- /**
- * Select Strongbox keymaster device, which as of this writing the the highest security level
- * available an android devices. If neither FLAG_STRONGBOX nor FLAG_SOFTWARE is provided
- * A TEE based keymaster implementation is implied.
- *
- * Need to be in sync with KeyStoreFlag in system/security/keystore/include/keystore/keystore.h
- */
- public static final int FLAG_STRONGBOX = 1 << 4;
-
// States
public enum State {
@UnsupportedAppUsage
@@ -157,853 +46,87 @@
UNINITIALIZED
};
- private int mError = NO_ERROR;
-
- private final IKeystoreService mBinder;
- private final Context mContext;
-
- private IBinder mToken;
-
- private KeyStore(IKeystoreService binder) {
- mBinder = binder;
- mContext = getApplicationContext();
- }
-
- @UnsupportedAppUsage
- public static Context getApplicationContext() {
- Application application = ActivityThread.currentApplication();
- if (application == null) {
- throw new IllegalStateException(
- "Failed to obtain application Context from ActivityThread");
- }
- return application;
- }
+ private static final KeyStore KEY_STORE = new KeyStore();
@UnsupportedAppUsage
public static KeyStore getInstance() {
- IKeystoreService keystore = IKeystoreService.Stub.asInterface(ServiceManager
- .getService("android.security.keystore"));
- return new KeyStore(keystore);
+ return KEY_STORE;
}
- private synchronized IBinder getToken() {
- if (mToken == null) {
- mToken = new Binder();
- }
- return mToken;
- }
-
+ /** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public State state(int userId) {
- final int ret;
- try {
- if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
- int userState = AndroidKeyStoreMaintenance.getState(userId);
- switch (userState) {
- case UserState.UNINITIALIZED:
- return KeyStore.State.UNINITIALIZED;
- case UserState.LSKF_UNLOCKED:
- return KeyStore.State.UNLOCKED;
- case UserState.LSKF_LOCKED:
- return KeyStore.State.LOCKED;
- default:
- throw new AssertionError(userState);
- }
- }
- ret = mBinder.getState(userId);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- throw new AssertionError(e);
- }
-
- switch (ret) {
- case NO_ERROR: return State.UNLOCKED;
- case LOCKED: return State.LOCKED;
- case UNINITIALIZED: return State.UNINITIALIZED;
- default: throw new AssertionError(mError);
+ int userState = AndroidKeyStoreMaintenance.getState(userId);
+ switch (userState) {
+ case UserState.UNINITIALIZED:
+ return KeyStore.State.UNINITIALIZED;
+ case UserState.LSKF_UNLOCKED:
+ return KeyStore.State.UNLOCKED;
+ case UserState.LSKF_LOCKED:
+ return KeyStore.State.LOCKED;
+ default:
+ throw new AssertionError(userState);
}
}
+ /** @hide */
@UnsupportedAppUsage
public State state() {
return state(UserHandle.myUserId());
}
- public boolean isUnlocked() {
- return state() == State.UNLOCKED;
- }
-
- public byte[] get(String key, int uid) {
- return get(key, uid, false);
- }
-
+ /** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public byte[] get(String key) {
- return get(key, UID_SELF);
+ return null;
}
- public byte[] get(String key, int uid, boolean suppressKeyNotFoundWarning) {
- try {
- key = key != null ? key : "";
- return mBinder.get(key, uid);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (android.os.ServiceSpecificException e) {
- if (!suppressKeyNotFoundWarning || e.errorCode != KEY_NOT_FOUND) {
- Log.w(TAG, "KeyStore exception", e);
- }
- return null;
- }
- }
-
- public byte[] get(String key, boolean suppressKeyNotFoundWarning) {
- return get(key, UID_SELF, suppressKeyNotFoundWarning);
- }
-
-
- public boolean put(String key, byte[] value, int uid, int flags) {
- return insert(key, value, uid, flags) == NO_ERROR;
- }
-
- public int insert(String key, byte[] value, int uid, int flags) {
- try {
- if (value == null) {
- value = new byte[0];
- }
- int error = mBinder.insert(key, value, uid, flags);
- if (error == KEY_ALREADY_EXISTS) {
- mBinder.del(key, uid);
- error = mBinder.insert(key, value, uid, flags);
- }
- return error;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- }
- }
-
- int delete2(String key, int uid) {
- try {
- return mBinder.del(key, uid);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- }
- }
-
- public boolean delete(String key, int uid) {
- int ret = delete2(key, uid);
- return ret == NO_ERROR || ret == KEY_NOT_FOUND;
- }
-
+ /** @hide */
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean delete(String key) {
- return delete(key, UID_SELF);
- }
-
- public boolean contains(String key, int uid) {
- try {
- return mBinder.exist(key, uid) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- public boolean contains(String key) {
- return contains(key, UID_SELF);
- }
-
- /**
- * List all entries in the keystore for {@code uid} starting with {@code prefix}.
- */
- public String[] list(String prefix, int uid) {
- try {
- return mBinder.list(prefix, uid);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (android.os.ServiceSpecificException e) {
- Log.w(TAG, "KeyStore exception", e);
- return null;
- }
+ return false;
}
/**
* List uids of all keys that are auth bound to the current user.
* Only system is allowed to call this method.
+ * @hide
+ * @deprecated This function always returns null.
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public int[] listUidsOfAuthBoundKeys() {
- // uids are returned as a list of strings because list of integers
- // as an output parameter is not supported by aidl-cpp.
- List<String> uidsOut = new ArrayList<>();
- try {
- int rc = mBinder.listUidsOfAuthBoundKeys(uidsOut);
- if (rc != NO_ERROR) {
- Log.w(TAG, String.format("listUidsOfAuthBoundKeys failed with error code %d", rc));
- return null;
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (android.os.ServiceSpecificException e) {
- Log.w(TAG, "KeyStore exception", e);
- return null;
- }
- // Turn list of strings into an array of uid integers.
- return uidsOut.stream().mapToInt(Integer::parseInt).toArray();
- }
-
- public String[] list(String prefix) {
- return list(prefix, UID_SELF);
+ return null;
}
+
/**
- * Attempt to lock the keystore for {@code user}.
- *
- * @param userId Android user to lock.
- * @return whether {@code user}'s keystore was locked.
+ * @hide
+ * @deprecated This function has no effect.
*/
- public boolean lock(int userId) {
- try {
- return mBinder.lock(userId) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- public boolean lock() {
- return lock(UserHandle.myUserId());
- }
-
- /**
- * Attempt to unlock the keystore for {@code user} with the password {@code password}.
- * This is required before keystore entries created with FLAG_ENCRYPTED can be accessed or
- * created.
- *
- * @param userId Android user ID to operate on
- * @param password user's keystore password. Should be the most recent value passed to
- * {@link #onUserPasswordChanged} for the user.
- *
- * @return whether the keystore was unlocked.
- */
- public boolean unlock(int userId, String password) {
- try {
- password = password != null ? password : "";
- mError = mBinder.unlock(userId, password);
- return mError == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public boolean unlock(String password) {
- return unlock(UserHandle.getUserId(Process.myUid()), password);
+ return false;
}
/**
- * Check if the keystore for {@code userId} is empty.
+ *
+ * @return
+ * @deprecated This function always returns true.
+ * @hide
*/
- public boolean isEmpty(int userId) {
- try {
- return mBinder.isEmpty(userId) != 0;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023)
public boolean isEmpty() {
- return isEmpty(UserHandle.myUserId());
- }
-
- public String grant(String key, int uid) {
- try {
- String grantAlias = mBinder.grant(key, uid);
- if (grantAlias == "") return null;
- return grantAlias;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- }
- }
-
- public boolean ungrant(String key, int uid) {
- try {
- return mBinder.ungrant(key, uid) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- /**
- * Returns the last modification time of the key in milliseconds since the
- * epoch. Will return -1L if the key could not be found or other error.
- */
- public long getmtime(String key, int uid) {
- try {
- final long millis = mBinder.getmtime(key, uid);
- if (millis == -1L) {
- return -1L;
- }
-
- return millis * 1000L;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return -1L;
- }
- }
-
- public long getmtime(String key) {
- return getmtime(key, UID_SELF);
- }
-
- // TODO: remove this when it's removed from Settings
- public boolean isHardwareBacked() {
- return isHardwareBacked("RSA");
- }
-
- public boolean isHardwareBacked(String keyType) {
- try {
- return mBinder.is_hardware_backed(keyType.toUpperCase(Locale.US)) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- public boolean clearUid(int uid) {
- try {
- if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
- return AndroidKeyStoreMaintenance.clearNamespace(Domain.APP, uid) == 0;
- }
- return mBinder.clear_uid(uid) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- public int getLastError() {
- return mError;
- }
-
- public boolean addRngEntropy(byte[] data, int flags) {
- KeystoreResultPromise promise = new KeystoreResultPromise();
- try {
- mBinder.asBinder().linkToDeath(promise, 0);
- int errorCode = mBinder.addRngEntropy(promise, data, flags);
- if (errorCode == NO_ERROR) {
- return interruptedPreservingGet(promise.getFuture()).getErrorCode() == NO_ERROR;
- } else {
- return false;
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- } catch (ExecutionException e) {
- Log.e(TAG, "AddRngEntropy completed with exception", e);
- return false;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
-
- private class KeyCharacteristicsCallbackResult {
- private KeystoreResponse keystoreResponse;
- private KeyCharacteristics keyCharacteristics;
-
- public KeyCharacteristicsCallbackResult(KeystoreResponse keystoreResponse,
- KeyCharacteristics keyCharacteristics) {
- this.keystoreResponse = keystoreResponse;
- this.keyCharacteristics = keyCharacteristics;
- }
-
- public KeystoreResponse getKeystoreResponse() {
- return keystoreResponse;
- }
-
- public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
- this.keystoreResponse = keystoreResponse;
- }
-
- public KeyCharacteristics getKeyCharacteristics() {
- return keyCharacteristics;
- }
-
- public void setKeyCharacteristics(KeyCharacteristics keyCharacteristics) {
- this.keyCharacteristics = keyCharacteristics;
- }
- }
-
- private class KeyCharacteristicsPromise
- extends android.security.keystore.IKeystoreKeyCharacteristicsCallback.Stub
- implements IBinder.DeathRecipient {
- final private CompletableFuture<KeyCharacteristicsCallbackResult> future =
- new CompletableFuture<KeyCharacteristicsCallbackResult>();
- @Override
- public void onFinished(KeystoreResponse keystoreResponse,
- KeyCharacteristics keyCharacteristics)
- throws android.os.RemoteException {
- future.complete(
- new KeyCharacteristicsCallbackResult(keystoreResponse, keyCharacteristics));
- }
- 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 {
- KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
- 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 = interruptedPreservingGet(promise.getFuture());
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
-
- error = result.getKeystoreResponse().getErrorCode();
- if (error != NO_ERROR) {
- Log.e(TAG, "generateKeyInternal failed on response " + error);
- return error;
- }
- KeyCharacteristics characteristics = result.getKeyCharacteristics();
- if (characteristics == null) {
- Log.e(TAG, "generateKeyInternal got empty key characteristics " + error);
- return SYSTEM_ERROR;
- }
- outCharacteristics.shallowCopyFrom(characteristics);
- return NO_ERROR;
- }
-
- public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int uid,
- int flags, KeyCharacteristics outCharacteristics) {
- try {
- entropy = entropy != null ? entropy : new byte[0];
- args = args != null ? args : new KeymasterArguments();
- int error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
- if (error == KEY_ALREADY_EXISTS) {
- mBinder.del(alias, uid);
- error = generateKeyInternal(alias, args, entropy, uid, flags, outCharacteristics);
- }
- return error;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "generateKey completed with exception", e);
- return SYSTEM_ERROR;
- }
- }
-
- public int generateKey(String alias, KeymasterArguments args, byte[] entropy, int flags,
- KeyCharacteristics outCharacteristics) {
- return generateKey(alias, args, entropy, UID_SELF, flags, outCharacteristics);
- }
-
- 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]);
-
- int error = mBinder.getKeyCharacteristics(promise, alias, clientId, appId, uid);
- if (error != NO_ERROR) return error;
-
- KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
- error = result.getKeystoreResponse().getErrorCode();
- if (error != NO_ERROR) return error;
-
- KeyCharacteristics characteristics = result.getKeyCharacteristics();
- if (characteristics == null) return SYSTEM_ERROR;
- outCharacteristics.shallowCopyFrom(characteristics);
- return NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "GetKeyCharacteristics completed with exception", e);
- return SYSTEM_ERROR;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
-
- public int getKeyCharacteristics(String alias, KeymasterBlob clientId, KeymasterBlob appId,
- KeyCharacteristics outCharacteristics) {
- return getKeyCharacteristics(alias, clientId, appId, UID_SELF, outCharacteristics);
- }
-
- private int importKeyInternal(String alias, KeymasterArguments args, int format, byte[] keyData,
- int uid, int flags, KeyCharacteristics outCharacteristics)
- throws RemoteException, ExecutionException {
- 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 = interruptedPreservingGet(promise.getFuture());
-
- error = result.getKeystoreResponse().getErrorCode();
- if (error != NO_ERROR) return error;
-
- KeyCharacteristics characteristics = result.getKeyCharacteristics();
- 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,
- int uid, int flags, KeyCharacteristics outCharacteristics) {
- try {
- int error = importKeyInternal(alias, args, format, keyData, uid, flags,
- outCharacteristics);
- if (error == KEY_ALREADY_EXISTS) {
- mBinder.del(alias, uid);
- error = importKeyInternal(alias, args, format, keyData, uid, flags,
- outCharacteristics);
- }
- return error;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "ImportKey completed with exception", e);
- return SYSTEM_ERROR;
- }
- }
-
- public int importKey(String alias, KeymasterArguments args, int format, byte[] keyData,
- int flags, KeyCharacteristics outCharacteristics) {
- return importKey(alias, args, format, keyData, UID_SELF, flags, outCharacteristics);
- }
-
- private String getAlgorithmFromPKCS8(byte[] keyData) {
- try {
- final ASN1InputStream bIn = new ASN1InputStream(new ByteArrayInputStream(keyData));
- final PrivateKeyInfo pki = PrivateKeyInfo.getInstance(bIn.readObject());
- final String algOid = pki.getPrivateKeyAlgorithm().getAlgorithm().getId();
- return new AlgorithmId(new ObjectIdentifier(algOid)).getName();
- } catch (IOException e) {
- Log.e(TAG, "getAlgorithmFromPKCS8 Failed to parse key data");
- Log.e(TAG, Log.getStackTraceString(e));
- return null;
- }
- }
-
- private KeymasterArguments makeLegacyArguments(String algorithm) {
- KeymasterArguments args = new KeymasterArguments();
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
- KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(algorithm));
- args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_SIGN);
- args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_VERIFY);
- args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_ENCRYPT);
- args.addEnum(KeymasterDefs.KM_TAG_PURPOSE, KeymasterDefs.KM_PURPOSE_DECRYPT);
- args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_NONE);
- if (algorithm.equalsIgnoreCase(KeyProperties.KEY_ALGORITHM_RSA)) {
- args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
- args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
- args.addEnum(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_PSS);
- }
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
- args.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
- args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
- args.addDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
- args.addDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME, new Date(Long.MAX_VALUE));
- args.addDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, new Date(0));
- return args;
- }
-
- public boolean importKey(String alias, byte[] keyData, int uid, int flags) {
- String algorithm = getAlgorithmFromPKCS8(keyData);
- if (algorithm == null) return false;
- KeymasterArguments args = makeLegacyArguments(algorithm);
- KeyCharacteristics out = new KeyCharacteristics();
- int result = importKey(alias, args, KeymasterDefs.KM_KEY_FORMAT_PKCS8, keyData, uid,
- flags, out);
- if (result != NO_ERROR) {
- Log.e(TAG, Log.getStackTraceString(
- new KeyStoreException(result, "legacy key import failed")));
- return false;
- }
return true;
}
- private int importWrappedKeyInternal(String wrappedKeyAlias, byte[] wrappedKey,
- String wrappingKeyAlias,
- byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid,
- KeyCharacteristics outCharacteristics)
- throws RemoteException, ExecutionException {
- KeyCharacteristicsPromise promise = new KeyCharacteristicsPromise();
- mBinder.asBinder().linkToDeath(promise, 0);
- try {
- int error = mBinder.importWrappedKey(promise, wrappedKeyAlias, wrappedKey,
- wrappingKeyAlias, maskingKey, args, rootSid, fingerprintSid);
- if (error != NO_ERROR) return error;
-
- KeyCharacteristicsCallbackResult result = interruptedPreservingGet(promise.getFuture());
-
- error = result.getKeystoreResponse().getErrorCode();
- if (error != NO_ERROR) return error;
-
- KeyCharacteristics characteristics = result.getKeyCharacteristics();
- 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,
- String wrappingKeyAlias,
- byte[] maskingKey, KeymasterArguments args, long rootSid, long fingerprintSid, int uid,
- KeyCharacteristics outCharacteristics) {
- // TODO b/119217337 uid parameter gets silently ignored.
- try {
- int error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
- maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
- if (error == KEY_ALREADY_EXISTS) {
- mBinder.del(wrappedKeyAlias, UID_SELF);
- error = importWrappedKeyInternal(wrappedKeyAlias, wrappedKey, wrappingKeyAlias,
- maskingKey, args, rootSid, fingerprintSid, outCharacteristics);
- }
- return error;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "ImportWrappedKey completed with exception", e);
- return SYSTEM_ERROR;
- }
- }
-
- private class ExportKeyPromise
- 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 {
- future.complete(exportKeyResult);
- }
- 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]);
- int error = mBinder.exportKey(promise, alias, format, clientId, appId, uid);
- if (error == NO_ERROR) {
- return interruptedPreservingGet(promise.getFuture());
- } else {
- return new ExportResult(error);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (ExecutionException 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,
- KeymasterBlob appId) {
- return exportKey(alias, format, clientId, appId, UID_SELF);
- }
-
- private class OperationPromise
- 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 {
- future.complete(operationResult);
- }
- 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];
- int errorCode = mBinder.begin(promise, getToken(), alias, purpose, pruneable, args,
- entropy, uid);
- if (errorCode == NO_ERROR) {
- return interruptedPreservingGet(promise.getFuture());
- } else {
- return new OperationResult(errorCode);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (ExecutionException e) {
- Log.e(TAG, "Begin completed with exception", e);
- return null;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
-
- public OperationResult begin(String alias, int purpose, boolean pruneable,
- KeymasterArguments args, byte[] entropy) {
- entropy = entropy != null ? entropy : new byte[0];
- args = args != null ? args : new KeymasterArguments();
- return begin(alias, purpose, pruneable, args, entropy, UID_SELF);
- }
-
- 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];
- int errorCode = mBinder.update(promise, token, arguments, input);
- if (errorCode == NO_ERROR) {
- return interruptedPreservingGet(promise.getFuture());
- } else {
- return new OperationResult(errorCode);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (ExecutionException e) {
- Log.e(TAG, "Update completed with exception", e);
- return null;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
-
/**
- * Android KeyStore finish operation.
- *
- * @param token Authentication token.
- * @param arguments Keymaster arguments
- * @param input Optional additional input data.
- * @param signature Optional signature to be verified.
- * @param entropy Optional additional entropy
- * @return OperationResult that will indicate success or error of the operation.
+ * Forwards the request to clear a UID to Keystore 2.0.
+ * @hide
*/
- public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] input,
- 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];
- input = input != null ? input : new byte[0];
- signature = signature != null ? signature : new byte[0];
- int errorCode = mBinder.finish(promise, token, arguments, input, signature, entropy);
- if (errorCode == NO_ERROR) {
- return interruptedPreservingGet(promise.getFuture());
- } else {
- return new OperationResult(errorCode);
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return null;
- } catch (ExecutionException e) {
- Log.e(TAG, "Finish completed with exception", e);
- return null;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
+ public boolean clearUid(int uid) {
+ return AndroidKeyStoreMaintenance.clearNamespace(Domain.APP, uid) == 0;
}
- public OperationResult finish(IBinder token, KeymasterArguments arguments, byte[] signature) {
- return finish(token, arguments, null, signature, null);
- }
-
- private class KeystoreResultPromise
- 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 {
- future.complete(keystoreResponse);
- }
- public final CompletableFuture<KeystoreResponse> getFuture() {
- return future;
- }
- @Override
- public void binderDied() {
- future.completeExceptionally(new RemoteException("Keystore died"));
- }
- };
-
- public int abort(IBinder token) {
- KeystoreResultPromise promise = new KeystoreResultPromise();
- try {
- mBinder.asBinder().linkToDeath(promise, 0);
- int errorCode = mBinder.abort(promise, token);
- if (errorCode == NO_ERROR) {
- return interruptedPreservingGet(promise.getFuture()).getErrorCode();
- } else {
- return errorCode;
- }
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "Abort completed with exception", e);
- return SYSTEM_ERROR;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
- }
/**
* Add an authentication record to the keystore authorization table.
@@ -1013,191 +136,7 @@
* a {@code KeymasterDefs.KM_ERROR_} value or {@code KeyStore} ResponseCode.
*/
public int addAuthToken(byte[] authToken) {
- try {
- Authorization.addAuthToken(authToken);
- return mBinder.addAuthToken(authToken);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- }
- }
-
- /**
- * Notify keystore that a user's password has changed.
- *
- * @param userId the user whose password changed.
- * @param newPassword the new password or "" if the password was removed.
- */
- public boolean onUserPasswordChanged(int userId, String newPassword) {
- // Parcel.cpp doesn't support deserializing null strings and treats them as "". Make that
- // explicit here.
- if (newPassword == null) {
- newPassword = "";
- }
- try {
- return mBinder.onUserPasswordChanged(userId, newPassword) == NO_ERROR;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
- }
-
- /**
- * Notify keystore that a user was added.
- *
- * @param userId the new user.
- * @param parentId the parent of the new user, or -1 if the user has no parent. If parentId is
- * specified then the new user's keystore will be intialized with the same secure lockscreen
- * password as the parent.
- */
- public void onUserAdded(int userId, int parentId) {
- try {
- mBinder.onUserAdded(userId, parentId);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- }
- }
-
- /**
- * Notify keystore that a user was added.
- *
- * @param userId the new user.
- */
- public void onUserAdded(int userId) {
- onUserAdded(userId, -1);
- }
-
- /**
- * Notify keystore that a user was removed.
- *
- * @param userId the removed user.
- */
- public void onUserRemoved(int userId) {
- try {
- mBinder.onUserRemoved(userId);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- }
- }
-
- public boolean onUserPasswordChanged(String newPassword) {
- return onUserPasswordChanged(UserHandle.getUserId(Process.myUid()), newPassword);
- }
-
- /**
- * Notify keystore about the latest user locked state. This is to support keyguard-bound key.
- */
- public void onUserLockedStateChanged(int userHandle, boolean locked) {
- try {
- mBinder.onKeyguardVisibilityChanged(locked, userHandle);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to update user locked state " + userHandle, e);
- }
- }
-
- private class KeyAttestationCallbackResult {
- private KeystoreResponse keystoreResponse;
- private KeymasterCertificateChain certificateChain;
-
- public KeyAttestationCallbackResult(KeystoreResponse keystoreResponse,
- KeymasterCertificateChain certificateChain) {
- this.keystoreResponse = keystoreResponse;
- this.certificateChain = certificateChain;
- }
-
- public KeystoreResponse getKeystoreResponse() {
- return keystoreResponse;
- }
-
- public void setKeystoreResponse(KeystoreResponse keystoreResponse) {
- this.keystoreResponse = keystoreResponse;
- }
-
- public KeymasterCertificateChain getCertificateChain() {
- return certificateChain;
- }
-
- public void setCertificateChain(KeymasterCertificateChain certificateChain) {
- this.certificateChain = certificateChain;
- }
- }
-
- private class CertificateChainPromise
- extends android.security.keystore.IKeystoreCertificateChainCallback.Stub
- implements IBinder.DeathRecipient {
- final private CompletableFuture<KeyAttestationCallbackResult> future = new CompletableFuture<KeyAttestationCallbackResult>();
- @Override
- public void onFinished(KeystoreResponse keystoreResponse,
- KeymasterCertificateChain certificateChain) throws android.os.RemoteException {
- future.complete(new KeyAttestationCallbackResult(keystoreResponse, certificateChain));
- }
- 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();
- }
- int error = mBinder.attestKey(promise, alias, params);
- if (error != NO_ERROR) return error;
- KeyAttestationCallbackResult result = interruptedPreservingGet(promise.getFuture());
- error = result.getKeystoreResponse().getErrorCode();
- if (error == NO_ERROR) {
- outChain.shallowCopyFrom(result.getCertificateChain());
- }
- return error;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException 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();
- }
- int error = mBinder.attestDeviceIds(promise, params);
- if (error != NO_ERROR) return error;
- KeyAttestationCallbackResult result = interruptedPreservingGet(promise.getFuture());
- error = result.getKeystoreResponse().getErrorCode();
- if (error == NO_ERROR) {
- outChain.shallowCopyFrom(result.getCertificateChain());
- }
- return error;
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return SYSTEM_ERROR;
- } catch (ExecutionException e) {
- Log.e(TAG, "AttestDevicdeIds completed with exception", e);
- return SYSTEM_ERROR;
- } finally {
- mBinder.asBinder().unlinkToDeath(promise, 0);
- }
+ return Authorization.addAuthToken(authToken);
}
/**
@@ -1205,77 +144,6 @@
*/
public void onDeviceOffBody() {
AndroidKeyStoreMaintenance.onDeviceOffBody();
- try {
- mBinder.onDeviceOffBody();
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- }
- }
-
- // Keep in sync with confirmationui/1.0/types.hal.
- public static final int CONFIRMATIONUI_OK = 0;
- public static final int CONFIRMATIONUI_CANCELED = 1;
- public static final int CONFIRMATIONUI_ABORTED = 2;
- public static final int CONFIRMATIONUI_OPERATION_PENDING = 3;
- public static final int CONFIRMATIONUI_IGNORED = 4;
- public static final int CONFIRMATIONUI_SYSTEM_ERROR = 5;
- public static final int CONFIRMATIONUI_UNIMPLEMENTED = 6;
- public static final int CONFIRMATIONUI_UNEXPECTED = 7;
- public static final int CONFIRMATIONUI_UIERROR = 0x10000;
- public static final int CONFIRMATIONUI_UIERROR_MISSING_GLYPH = 0x10001;
- public static final int CONFIRMATIONUI_UIERROR_MESSAGE_TOO_LONG = 0x10002;
- public static final int CONFIRMATIONUI_UIERROR_MALFORMED_UTF8_ENCODING = 0x10003;
-
- /**
- * Requests keystore call into the confirmationui HAL to display a prompt.
- *
- * @param listener the binder to use for callbacks.
- * @param promptText the prompt to display.
- * @param extraData extra data / nonce from application.
- * @param locale the locale as a BCP 47 langauge tag.
- * @param uiOptionsAsFlags the UI options to use, as flags.
- * @return one of the {@code CONFIRMATIONUI_*} constants, for
- * example {@code KeyStore.CONFIRMATIONUI_OK}.
- */
- public int presentConfirmationPrompt(IBinder listener, String promptText, byte[] extraData,
- String locale, int uiOptionsAsFlags) {
- try {
- return mBinder.presentConfirmationPrompt(listener, promptText, extraData, locale,
- uiOptionsAsFlags);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return CONFIRMATIONUI_SYSTEM_ERROR;
- }
- }
-
- /**
- * Requests keystore call into the confirmationui HAL to cancel displaying a prompt.
- *
- * @param listener the binder passed to the {@link #presentConfirmationPrompt} method.
- * @return one of the {@code CONFIRMATIONUI_*} constants, for
- * example {@code KeyStore.CONFIRMATIONUI_OK}.
- */
- public int cancelConfirmationPrompt(IBinder listener) {
- try {
- return mBinder.cancelConfirmationPrompt(listener);
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return CONFIRMATIONUI_SYSTEM_ERROR;
- }
- }
-
- /**
- * Requests keystore to check if the confirmationui HAL is available.
- *
- * @return whether the confirmationUI HAL is available.
- */
- public boolean isConfirmationPromptSupported() {
- try {
- return mBinder.isConfirmationPromptSupported();
- } catch (RemoteException e) {
- Log.w(TAG, "Cannot connect to keystore", e);
- return false;
- }
}
/**
@@ -1284,143 +152,6 @@
*/
@UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
public static KeyStoreException getKeyStoreException(int errorCode) {
- if (errorCode > 0) {
- // KeyStore layer error
- switch (errorCode) {
- case NO_ERROR:
- return new KeyStoreException(errorCode, "OK");
- case LOCKED:
- return new KeyStoreException(errorCode, "User authentication required");
- case UNINITIALIZED:
- return new KeyStoreException(errorCode, "Keystore not initialized");
- case SYSTEM_ERROR:
- return new KeyStoreException(errorCode, "System error");
- case PERMISSION_DENIED:
- return new KeyStoreException(errorCode, "Permission denied");
- case KEY_NOT_FOUND:
- return new KeyStoreException(errorCode, "Key not found");
- case VALUE_CORRUPTED:
- return new KeyStoreException(errorCode, "Key blob corrupted");
- case OP_AUTH_NEEDED:
- return new KeyStoreException(errorCode, "Operation requires authorization");
- case KEY_PERMANENTLY_INVALIDATED:
- return new KeyStoreException(errorCode, "Key permanently invalidated");
- default:
- return new KeyStoreException(errorCode, String.valueOf(errorCode));
- }
- } else {
- // Keymaster layer error
- switch (errorCode) {
- case KeymasterDefs.KM_ERROR_INVALID_AUTHORIZATION_TIMEOUT:
- // The name of this parameter significantly differs between Keymaster and
- // framework APIs. Use the framework wording to make life easier for developers.
- return new KeyStoreException(errorCode,
- "Invalid user authentication validity duration");
- default:
- return new KeyStoreException(errorCode,
- KeymasterDefs.getErrorMessage(errorCode));
- }
- }
- }
-
- /**
- * Returns an {@link InvalidKeyException} corresponding to the provided
- * {@link KeyStoreException}.
- */
- public InvalidKeyException getInvalidKeyException(
- String keystoreKeyAlias, int uid, KeyStoreException e) {
- switch (e.getErrorCode()) {
- case LOCKED:
- return new UserNotAuthenticatedException();
- case KeymasterDefs.KM_ERROR_KEY_EXPIRED:
- return new KeyExpiredException();
- case KeymasterDefs.KM_ERROR_KEY_NOT_YET_VALID:
- return new KeyNotYetValidException();
- case KeymasterDefs.KM_ERROR_KEY_USER_NOT_AUTHENTICATED:
- case OP_AUTH_NEEDED:
- {
- // We now need to determine whether the key/operation can become usable if user
- // authentication is performed, or whether it can never become usable again.
- // User authentication requirements are contained in the key's characteristics. We
- // need to check whether these requirements can be be satisfied by asking the user
- // to authenticate.
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- int getKeyCharacteristicsErrorCode =
- getKeyCharacteristics(keystoreKeyAlias, null, null, uid,
- keyCharacteristics);
- if (getKeyCharacteristicsErrorCode != NO_ERROR) {
- return new InvalidKeyException(
- "Failed to obtained key characteristics",
- getKeyStoreException(getKeyCharacteristicsErrorCode));
- }
- List<BigInteger> keySids =
- keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
- if (keySids.isEmpty()) {
- // Key is not bound to any SIDs -- no amount of authentication will help here.
- return new KeyPermanentlyInvalidatedException();
- }
- long rootSid = GateKeeper.getSecureUserId();
- if ((rootSid != 0) && (keySids.contains(KeymasterArguments.toUint64(rootSid)))) {
- // One of the key's SIDs is the current root SID -- user can be authenticated
- // against that SID.
- return new UserNotAuthenticatedException();
- }
-
- final BiometricManager bm = mContext.getSystemService(BiometricManager.class);
- long[] biometricSids = bm.getAuthenticatorIds();
-
- // The key must contain every biometric SID. This is because the current API surface
- // treats all biometrics (capable of keystore integration) equally. e.g. if the
- // device has multiple keystore-capable sensors, and one of the sensor's SIDs
- // changed, 1) there is no way for a developer to specify authentication with a
- // specific sensor (the one that hasn't changed), and 2) currently the only
- // signal to developers is the UserNotAuthenticatedException, which doesn't
- // indicate a specific sensor.
- boolean canUnlockViaBiometrics = true;
- for (long sid : biometricSids) {
- if (!keySids.contains(KeymasterArguments.toUint64(sid))) {
- canUnlockViaBiometrics = false;
- break;
- }
- }
-
- if (canUnlockViaBiometrics) {
- // All of the biometric SIDs are contained in the key's SIDs.
- return new UserNotAuthenticatedException();
- }
-
- // None of the key's SIDs can ever be authenticated
- return new KeyPermanentlyInvalidatedException();
- }
- case UNINITIALIZED:
- return new KeyPermanentlyInvalidatedException();
- default:
- return new InvalidKeyException("Keystore operation failed", e);
- }
- }
-
- /**
- * Returns an {@link InvalidKeyException} corresponding to the provided keystore/keymaster error
- * code.
- */
- public InvalidKeyException getInvalidKeyException(String keystoreKeyAlias, int uid,
- int errorCode) {
- return getInvalidKeyException(keystoreKeyAlias, uid, getKeyStoreException(errorCode));
- }
-
- private static <R> R interruptedPreservingGet(CompletableFuture<R> future)
- throws ExecutionException {
- boolean wasInterrupted = false;
- while (true) {
- try {
- R result = future.get();
- if (wasInterrupted) {
- Thread.currentThread().interrupt();
- }
- return result;
- } catch (InterruptedException e) {
- wasInterrupted = true;
- }
- }
+ return new KeyStoreException(-10000, "Should not be called.");
}
}
diff --git a/keystore/java/android/security/LegacyVpnProfileStore.java b/keystore/java/android/security/LegacyVpnProfileStore.java
index 41cfb27..1d2738e 100644
--- a/keystore/java/android/security/LegacyVpnProfileStore.java
+++ b/keystore/java/android/security/LegacyVpnProfileStore.java
@@ -19,7 +19,6 @@
import android.annotation.NonNull;
import android.os.ServiceManager;
import android.os.ServiceSpecificException;
-import android.security.keystore.AndroidKeyStoreProvider;
import android.security.vpnprofilestore.IVpnProfileStore;
import android.util.Log;
@@ -53,13 +52,8 @@
*/
public static boolean put(@NonNull String alias, @NonNull byte[] profile) {
try {
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- getService().put(alias, profile);
- return true;
- } else {
- return KeyStore.getInstance().put(
- alias, profile, KeyStore.UID_SELF, 0);
- }
+ getService().put(alias, profile);
+ return true;
} catch (Exception e) {
Log.e(TAG, "Failed to put vpn profile.", e);
return false;
@@ -77,11 +71,7 @@
*/
public static byte[] get(@NonNull String alias) {
try {
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- return getService().get(alias);
- } else {
- return KeyStore.getInstance().get(alias, true /* suppressKeyNotFoundWarning */);
- }
+ return getService().get(alias);
} catch (ServiceSpecificException e) {
if (e.errorCode != PROFILE_NOT_FOUND) {
Log.e(TAG, "Failed to get vpn profile.", e);
@@ -100,12 +90,8 @@
*/
public static boolean remove(@NonNull String alias) {
try {
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- getService().remove(alias);
- return true;
- } else {
- return KeyStore.getInstance().delete(alias);
- }
+ getService().remove(alias);
+ return true;
} catch (ServiceSpecificException e) {
if (e.errorCode != PROFILE_NOT_FOUND) {
Log.e(TAG, "Failed to remove vpn profile.", e);
@@ -124,16 +110,11 @@
*/
public static @NonNull String[] list(@NonNull String prefix) {
try {
- if (AndroidKeyStoreProvider.isKeystore2Enabled()) {
- final String[] aliases = getService().list(prefix);
- for (int i = 0; i < aliases.length; ++i) {
- aliases[i] = aliases[i].substring(prefix.length());
- }
- return aliases;
- } else {
- final String[] result = KeyStore.getInstance().list(prefix);
- return result != null ? result : new String[0];
+ final String[] aliases = getService().list(prefix);
+ for (int i = 0; i < aliases.length; ++i) {
+ aliases[i] = aliases[i].substring(prefix.length());
}
+ return aliases;
} catch (Exception e) {
Log.e(TAG, "Failed to list vpn profiles.", e);
}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java
deleted file mode 100644
index 01fd062..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStore3DESCipherSpi.java
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * Copyright (C) 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.keystore;
-
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.util.Arrays;
-
-import javax.crypto.CipherSpi;
-import javax.crypto.spec.IvParameterSpec;
-
-/**
- * Base class for Android Keystore 3DES {@link CipherSpi} implementations.
- *
- * @hide
- */
-public class AndroidKeyStore3DESCipherSpi extends AndroidKeyStoreCipherSpiBase {
-
- private static final int BLOCK_SIZE_BYTES = 8;
-
- private final int mKeymasterBlockMode;
- private final int mKeymasterPadding;
- /** Whether this transformation requires an IV. */
- private final boolean mIvRequired;
-
- private byte[] mIv;
-
- /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */
- private boolean mIvHasBeenUsed;
-
- AndroidKeyStore3DESCipherSpi(
- int keymasterBlockMode,
- int keymasterPadding,
- boolean ivRequired) {
- mKeymasterBlockMode = keymasterBlockMode;
- mKeymasterPadding = keymasterPadding;
- mIvRequired = ivRequired;
- }
-
- abstract static class ECB extends AndroidKeyStore3DESCipherSpi {
- protected ECB(int keymasterPadding) {
- super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false);
- }
-
- public static class NoPadding extends ECB {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
- }
-
- public static class PKCS7Padding extends ECB {
- public PKCS7Padding() {
- super(KeymasterDefs.KM_PAD_PKCS7);
- }
- }
- }
-
- abstract static class CBC extends AndroidKeyStore3DESCipherSpi {
- protected CBC(int keymasterPadding) {
- super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true);
- }
-
- public static class NoPadding extends CBC {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
- }
-
- public static class PKCS7Padding extends CBC {
- public PKCS7Padding() {
- super(KeymasterDefs.KM_PAD_PKCS7);
- }
- }
- }
-
- @Override
- protected void initKey(int i, Key key) throws InvalidKeyException {
- if (!(key instanceof AndroidKeyStoreSecretKey)) {
- throw new InvalidKeyException(
- "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
- }
- if (!KeyProperties.KEY_ALGORITHM_3DES.equalsIgnoreCase(key.getAlgorithm())) {
- throw new InvalidKeyException(
- "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " +
- KeyProperties.KEY_ALGORITHM_3DES + " supported");
- }
- setKey((AndroidKeyStoreSecretKey) key);
- }
-
- @Override
- protected int engineGetBlockSize() {
- return BLOCK_SIZE_BYTES;
- }
-
- @Override
- protected int engineGetOutputSize(int inputLen) {
- return inputLen + 3 * BLOCK_SIZE_BYTES;
- }
-
- @Override
- protected final byte[] engineGetIV() {
- return ArrayUtils.cloneIfNotEmpty(mIv);
- }
-
- @Override
- protected AlgorithmParameters engineGetParameters() {
- if (!mIvRequired) {
- return null;
- }
- if ((mIv != null) && (mIv.length > 0)) {
- try {
- AlgorithmParameters params = AlgorithmParameters.getInstance("DESede");
- params.init(new IvParameterSpec(mIv));
- return params;
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain 3DES AlgorithmParameters", e);
- } catch (InvalidParameterSpecException e) {
- throw new ProviderException(
- "Failed to initialize 3DES AlgorithmParameters with an IV",
- e);
- }
- }
- return null;
- }
-
- @Override
- protected void initAlgorithmSpecificParameters() throws InvalidKeyException {
- if (!mIvRequired) {
- return;
- }
-
- // IV is used
- if (!isEncrypting()) {
- throw new InvalidKeyException("IV required when decrypting"
- + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
- }
- }
-
- @Override
- protected void initAlgorithmSpecificParameters(AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException {
- if (!mIvRequired) {
- if (params != null) {
- throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
- }
- return;
- }
-
- // IV is used
- if (params == null) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException(
- "IvParameterSpec must be provided when decrypting");
- }
- return;
- }
- if (!(params instanceof IvParameterSpec)) {
- throw new InvalidAlgorithmParameterException("Only IvParameterSpec supported");
- }
- mIv = ((IvParameterSpec) params).getIV();
- if (mIv == null) {
- throw new InvalidAlgorithmParameterException("Null IV in IvParameterSpec");
- }
- }
-
- @Override
- protected void initAlgorithmSpecificParameters(AlgorithmParameters params)
- throws InvalidAlgorithmParameterException {
- if (!mIvRequired) {
- if (params != null) {
- throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
- }
- return;
- }
-
- // IV is used
- if (params == null) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException("IV required when decrypting"
- + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
- }
- return;
- }
-
- if (!"DESede".equalsIgnoreCase(params.getAlgorithm())) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm()
- + ". Supported: DESede");
- }
-
- IvParameterSpec ivSpec;
- try {
- ivSpec = params.getParameterSpec(IvParameterSpec.class);
- } catch (InvalidParameterSpecException e) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException("IV required when decrypting"
- + ", but not found in parameters: " + params, e);
- }
- mIv = null;
- return;
- }
- mIv = ivSpec.getIV();
- if (mIv == null) {
- throw new InvalidAlgorithmParameterException("Null IV in AlgorithmParameters");
- }
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForBegin() {
- if ((mIvRequired) && (mIv == null) && (isEncrypting())) {
- // IV will need to be generated
- return BLOCK_SIZE_BYTES;
- }
-
- return 0;
- }
-
- @Override
- protected int getAdditionalEntropyAmountForFinish() {
- return 0;
- }
-
- @Override
- protected void addAlgorithmSpecificParametersToBegin(KeymasterArguments keymasterArgs) {
- if ((isEncrypting()) && (mIvRequired) && (mIvHasBeenUsed)) {
- // IV is being reused for encryption: this violates security best practices.
- throw new IllegalStateException(
- "IV has already been used. Reusing IV in encryption mode violates security best"
- + " practices.");
- }
-
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_3DES);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
- if ((mIvRequired) && (mIv != null)) {
- keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv);
- }
- }
-
- @Override
- protected void loadAlgorithmSpecificParametersFromBeginResult(
- KeymasterArguments keymasterArgs) {
- mIvHasBeenUsed = true;
-
- // NOTE: Keymaster doesn't always return an IV, even if it's used.
- byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null);
- if ((returnedIv != null) && (returnedIv.length == 0)) {
- returnedIv = null;
- }
-
- if (mIvRequired) {
- if (mIv == null) {
- mIv = returnedIv;
- } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
- throw new ProviderException("IV in use differs from provided IV");
- }
- } else {
- if (returnedIv != null) {
- throw new ProviderException(
- "IV in use despite IV not being used by this transformation");
- }
- }
- }
-
- @Override
- protected final void resetAll() {
- mIv = null;
- mIvHasBeenUsed = false;
- super.resetAll();
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
deleted file mode 100644
index feb6101..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-import android.security.keystore.KeyStoreCryptoOperationChunkedStreamer.Stream;
-
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.util.Arrays;
-
-import javax.crypto.CipherSpi;
-import javax.crypto.spec.GCMParameterSpec;
-
-/**
- * Base class for Android Keystore authenticated AES {@link CipherSpi} implementations.
- *
- * @hide
- */
-abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
-
- abstract static class GCM extends AndroidKeyStoreAuthenticatedAESCipherSpi {
- static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96;
- private static final int MAX_SUPPORTED_TAG_LENGTH_BITS = 128;
- private static final int DEFAULT_TAG_LENGTH_BITS = 128;
- private static final int IV_LENGTH_BYTES = 12;
-
- private int mTagLengthBits = DEFAULT_TAG_LENGTH_BITS;
-
- GCM(int keymasterPadding) {
- super(KeymasterDefs.KM_MODE_GCM, keymasterPadding);
- }
-
- @Override
- protected final void resetAll() {
- mTagLengthBits = DEFAULT_TAG_LENGTH_BITS;
- super.resetAll();
- }
-
- @Override
- protected final void resetWhilePreservingInitState() {
- super.resetWhilePreservingInitState();
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters() throws InvalidKeyException {
- if (!isEncrypting()) {
- throw new InvalidKeyException("IV required when decrypting"
- + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
- }
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters(AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException {
- // IV is used
- if (params == null) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException(
- "GCMParameterSpec must be provided when decrypting");
- }
- return;
- }
- if (!(params instanceof GCMParameterSpec)) {
- throw new InvalidAlgorithmParameterException("Only GCMParameterSpec supported");
- }
- GCMParameterSpec spec = (GCMParameterSpec) params;
- byte[] iv = spec.getIV();
- if (iv == null) {
- throw new InvalidAlgorithmParameterException("Null IV in GCMParameterSpec");
- } else if (iv.length != IV_LENGTH_BYTES) {
- throw new InvalidAlgorithmParameterException("Unsupported IV length: "
- + iv.length + " bytes. Only " + IV_LENGTH_BYTES
- + " bytes long IV supported");
- }
- int tagLengthBits = spec.getTLen();
- if ((tagLengthBits < MIN_SUPPORTED_TAG_LENGTH_BITS)
- || (tagLengthBits > MAX_SUPPORTED_TAG_LENGTH_BITS)
- || ((tagLengthBits % 8) != 0)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported tag length: " + tagLengthBits + " bits"
- + ". Supported lengths: 96, 104, 112, 120, 128");
- }
- setIv(iv);
- mTagLengthBits = tagLengthBits;
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters(AlgorithmParameters params)
- throws InvalidAlgorithmParameterException {
- if (params == null) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException("IV required when decrypting"
- + ". Use GCMParameterSpec or GCM AlgorithmParameters to provide it.");
- }
- return;
- }
-
- if (!"GCM".equalsIgnoreCase(params.getAlgorithm())) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm()
- + ". Supported: GCM");
- }
-
- GCMParameterSpec spec;
- try {
- spec = params.getParameterSpec(GCMParameterSpec.class);
- } catch (InvalidParameterSpecException e) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException("IV and tag length required when"
- + " decrypting, but not found in parameters: " + params, e);
- }
- setIv(null);
- return;
- }
- initAlgorithmSpecificParameters(spec);
- }
-
- @Nullable
- @Override
- protected final AlgorithmParameters engineGetParameters() {
- byte[] iv = getIv();
- if ((iv != null) && (iv.length > 0)) {
- try {
- AlgorithmParameters params = AlgorithmParameters.getInstance("GCM");
- params.init(new GCMParameterSpec(mTagLengthBits, iv));
- return params;
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain GCM AlgorithmParameters", e);
- } catch (InvalidParameterSpecException e) {
- throw new ProviderException(
- "Failed to initialize GCM AlgorithmParameters", e);
- }
- }
- return null;
- }
-
- @NonNull
- @Override
- protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
- KeyStore keyStore, IBinder operationToken) {
- KeyStoreCryptoOperationStreamer streamer = new KeyStoreCryptoOperationChunkedStreamer(
- new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
- keyStore, operationToken), 0);
- if (isEncrypting()) {
- return streamer;
- } else {
- // When decrypting, to avoid leaking unauthenticated plaintext, do not return any
- // plaintext before ciphertext is authenticated by KeyStore.finish.
- return new BufferAllOutputUntilDoFinalStreamer(streamer);
- }
- }
-
- @NonNull
- @Override
- protected final KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer(
- KeyStore keyStore, IBinder operationToken) {
- return new KeyStoreCryptoOperationChunkedStreamer(
- new AdditionalAuthenticationDataStream(keyStore, operationToken), 0);
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForBegin() {
- if ((getIv() == null) && (isEncrypting())) {
- // IV will need to be generated
- return IV_LENGTH_BYTES;
- }
-
- return 0;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForFinish() {
- return 0;
- }
-
- @Override
- protected final void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs) {
- super.addAlgorithmSpecificParametersToBegin(keymasterArgs);
- keymasterArgs.addUnsignedInt(KeymasterDefs.KM_TAG_MAC_LENGTH, mTagLengthBits);
- }
-
- protected final int getTagLengthBits() {
- return mTagLengthBits;
- }
-
- public static final class NoPadding extends GCM {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
-
- @Override
- protected final int engineGetOutputSize(int inputLen) {
- int tagLengthBytes = (getTagLengthBits() + 7) / 8;
- long result;
- if (isEncrypting()) {
- result = getConsumedInputSizeBytes() - getProducedOutputSizeBytes() + inputLen
- + tagLengthBytes;
- } else {
- result = getConsumedInputSizeBytes() - getProducedOutputSizeBytes() + inputLen
- - tagLengthBytes;
- }
- if (result < 0) {
- return 0;
- } else if (result > Integer.MAX_VALUE) {
- return Integer.MAX_VALUE;
- }
- return (int) result;
- }
- }
- }
-
- private static final int BLOCK_SIZE_BYTES = 16;
-
- private final int mKeymasterBlockMode;
- private final int mKeymasterPadding;
-
- private byte[] mIv;
-
- /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */
- private boolean mIvHasBeenUsed;
-
- AndroidKeyStoreAuthenticatedAESCipherSpi(
- int keymasterBlockMode,
- int keymasterPadding) {
- mKeymasterBlockMode = keymasterBlockMode;
- mKeymasterPadding = keymasterPadding;
- }
-
- @Override
- protected void resetAll() {
- mIv = null;
- mIvHasBeenUsed = false;
- super.resetAll();
- }
-
- @Override
- protected final void initKey(int opmode, Key key) throws InvalidKeyException {
- if (!(key instanceof AndroidKeyStoreSecretKey)) {
- throw new InvalidKeyException(
- "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
- }
- if (!KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(key.getAlgorithm())) {
- throw new InvalidKeyException(
- "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " +
- KeyProperties.KEY_ALGORITHM_AES + " supported");
- }
- setKey((AndroidKeyStoreSecretKey) key);
- }
-
- @Override
- protected void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs) {
- if ((isEncrypting()) && (mIvHasBeenUsed)) {
- // IV is being reused for encryption: this violates security best practices.
- throw new IllegalStateException(
- "IV has already been used. Reusing IV in encryption mode violates security best"
- + " practices.");
- }
-
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
- if (mIv != null) {
- keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv);
- }
- }
-
- @Override
- protected final void loadAlgorithmSpecificParametersFromBeginResult(
- @NonNull KeymasterArguments keymasterArgs) {
- mIvHasBeenUsed = true;
-
- // NOTE: Keymaster doesn't always return an IV, even if it's used.
- byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null);
- if ((returnedIv != null) && (returnedIv.length == 0)) {
- returnedIv = null;
- }
-
- if (mIv == null) {
- mIv = returnedIv;
- } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
- throw new ProviderException("IV in use differs from provided IV");
- }
- }
-
- @Override
- protected final int engineGetBlockSize() {
- return BLOCK_SIZE_BYTES;
- }
-
- @Override
- protected final byte[] engineGetIV() {
- return ArrayUtils.cloneIfNotEmpty(mIv);
- }
-
- protected void setIv(byte[] iv) {
- mIv = iv;
- }
-
- protected byte[] getIv() {
- return mIv;
- }
-
- /**
- * {@link KeyStoreCryptoOperationStreamer} which buffers all output until {@code doFinal} from
- * which it returns all output in one go, provided {@code doFinal} succeeds.
- */
- private static class BufferAllOutputUntilDoFinalStreamer
- implements KeyStoreCryptoOperationStreamer {
-
- private final KeyStoreCryptoOperationStreamer mDelegate;
- private ByteArrayOutputStream mBufferedOutput = new ByteArrayOutputStream();
- private long mProducedOutputSizeBytes;
-
- private BufferAllOutputUntilDoFinalStreamer(KeyStoreCryptoOperationStreamer delegate) {
- mDelegate = delegate;
- }
-
- @Override
- public byte[] update(byte[] input, int inputOffset, int inputLength)
- throws KeyStoreException {
- byte[] output = mDelegate.update(input, inputOffset, inputLength);
- if (output != null) {
- try {
- mBufferedOutput.write(output);
- } catch (IOException e) {
- throw new ProviderException("Failed to buffer output", e);
- }
- }
- return EmptyArray.BYTE;
- }
-
- @Override
- public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
- byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
- byte[] output = mDelegate.doFinal(input, inputOffset, inputLength, signature,
- additionalEntropy);
- if (output != null) {
- try {
- mBufferedOutput.write(output);
- } catch (IOException e) {
- throw new ProviderException("Failed to buffer output", e);
- }
- }
- byte[] result = mBufferedOutput.toByteArray();
- mBufferedOutput.reset();
- mProducedOutputSizeBytes += result.length;
- return result;
- }
-
- @Override
- public long getConsumedInputSizeBytes() {
- return mDelegate.getConsumedInputSizeBytes();
- }
-
- @Override
- public long getProducedOutputSizeBytes() {
- return mProducedOutputSizeBytes;
- }
- }
-
- /**
- * Additional Authentication Data (AAD) stream via a KeyStore streaming operation. This stream
- * sends AAD into the KeyStore.
- */
- private static class AdditionalAuthenticationDataStream implements Stream {
-
- private final KeyStore mKeyStore;
- private final IBinder mOperationToken;
-
- private AdditionalAuthenticationDataStream(KeyStore keyStore, IBinder operationToken) {
- mKeyStore = keyStore;
- mOperationToken = operationToken;
- }
-
- @Override
- public OperationResult update(byte[] input) {
- KeymasterArguments keymasterArgs = new KeymasterArguments();
- keymasterArgs.addBytes(KeymasterDefs.KM_TAG_ASSOCIATED_DATA, input);
-
- // KeyStore does not reflect AAD in inputConsumed, but users of Stream rely on this
- // field. We fix this discrepancy here. KeyStore.update contract is that all of AAD
- // has been consumed if the method succeeds.
- OperationResult result = mKeyStore.update(mOperationToken, keymasterArgs, null);
- if (result.resultCode == KeyStore.NO_ERROR) {
- result = new OperationResult(
- result.resultCode,
- result.token,
- result.operationHandle,
- input.length, // inputConsumed
- result.output,
- result.outParams);
- }
- return result;
- }
-
- @Override
- public OperationResult finish(byte[] input, byte[] signature, byte[] additionalEntropy) {
- if ((additionalEntropy != null) && (additionalEntropy.length > 0)) {
- throw new ProviderException("AAD stream does not support additional entropy");
- }
- return new OperationResult(
- KeyStore.NO_ERROR,
- mOperationToken,
- 0, // operation handle -- nobody cares about this being returned from finish
- 0, // inputConsumed
- EmptyArray.BYTE, // output
- new KeymasterArguments() // additional params returned by finish
- );
- }
- }
-}
\ No newline at end of file
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
deleted file mode 100644
index 5730234..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreBCWorkaroundProvider.java
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import java.security.Provider;
-
-/**
- * {@link Provider} of JCA crypto operations operating on Android KeyStore keys.
- *
- * <p>This provider was separated out of {@link AndroidKeyStoreProvider} to work around the issue
- * that Bouncy Castle provider incorrectly declares that it accepts arbitrary keys (incl. Android
- * KeyStore ones). This causes JCA to select the Bouncy Castle's implementation of JCA crypto
- * operations for Android KeyStore keys unless Android KeyStore's own implementations are installed
- * as higher-priority than Bouncy Castle ones. The purpose of this provider is to do just that: to
- * offer crypto operations operating on Android KeyStore keys and to be installed at higher priority
- * than the Bouncy Castle provider.
- *
- * <p>Once Bouncy Castle provider is fixed, this provider can be merged into the
- * {@code AndroidKeyStoreProvider}.
- *
- * @hide
- */
-public class AndroidKeyStoreBCWorkaroundProvider extends Provider {
-
- // IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
- // classes when this provider is instantiated and installed early on during each app's
- // initialization process.
-
- private static final String PACKAGE_NAME = "android.security.keystore";
- private static final String KEYSTORE_SECRET_KEY_CLASS_NAME =
- PACKAGE_NAME + ".AndroidKeyStoreSecretKey";
- private static final String KEYSTORE_PRIVATE_KEY_CLASS_NAME =
- PACKAGE_NAME + ".AndroidKeyStorePrivateKey";
- private static final String KEYSTORE_PUBLIC_KEY_CLASS_NAME =
- PACKAGE_NAME + ".AndroidKeyStorePublicKey";
-
- private static final String DESEDE_SYSTEM_PROPERTY = "ro.hardware.keystore_desede";
-
- /** @hide */
- public AndroidKeyStoreBCWorkaroundProvider() {
- this("AndroidKeyStoreBCWorkaround");
- }
-
- /** @hide **/
- public AndroidKeyStoreBCWorkaroundProvider(String providerName) {
- super(providerName,
- 1.0,
- "Android KeyStore security provider to work around Bouncy Castle");
-
- // --------------------- javax.crypto.Mac
- putMacImpl("HmacSHA1", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA1");
- put("Alg.Alias.Mac.1.2.840.113549.2.7", "HmacSHA1");
- put("Alg.Alias.Mac.HMAC-SHA1", "HmacSHA1");
- put("Alg.Alias.Mac.HMAC/SHA1", "HmacSHA1");
-
- putMacImpl("HmacSHA224", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA224");
- put("Alg.Alias.Mac.1.2.840.113549.2.9", "HmacSHA224");
- put("Alg.Alias.Mac.HMAC-SHA224", "HmacSHA224");
- put("Alg.Alias.Mac.HMAC/SHA224", "HmacSHA224");
-
- putMacImpl("HmacSHA256", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA256");
- put("Alg.Alias.Mac.1.2.840.113549.2.9", "HmacSHA256");
- put("Alg.Alias.Mac.HMAC-SHA256", "HmacSHA256");
- put("Alg.Alias.Mac.HMAC/SHA256", "HmacSHA256");
-
- putMacImpl("HmacSHA384", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA384");
- put("Alg.Alias.Mac.1.2.840.113549.2.10", "HmacSHA384");
- put("Alg.Alias.Mac.HMAC-SHA384", "HmacSHA384");
- put("Alg.Alias.Mac.HMAC/SHA384", "HmacSHA384");
-
- putMacImpl("HmacSHA512", PACKAGE_NAME + ".AndroidKeyStoreHmacSpi$HmacSHA512");
- put("Alg.Alias.Mac.1.2.840.113549.2.11", "HmacSHA512");
- put("Alg.Alias.Mac.HMAC-SHA512", "HmacSHA512");
- put("Alg.Alias.Mac.HMAC/SHA512", "HmacSHA512");
-
- // --------------------- javax.crypto.Cipher
- putSymmetricCipherImpl("AES/ECB/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$ECB$NoPadding");
- putSymmetricCipherImpl("AES/ECB/PKCS7Padding",
- PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$ECB$PKCS7Padding");
-
- putSymmetricCipherImpl("AES/CBC/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CBC$NoPadding");
- putSymmetricCipherImpl("AES/CBC/PKCS7Padding",
- PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CBC$PKCS7Padding");
-
- putSymmetricCipherImpl("AES/CTR/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStoreUnauthenticatedAESCipherSpi$CTR$NoPadding");
-
- if ("true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY))) {
- putSymmetricCipherImpl("DESede/CBC/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$NoPadding");
- putSymmetricCipherImpl("DESede/CBC/PKCS7Padding",
- PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$CBC$PKCS7Padding");
-
- putSymmetricCipherImpl("DESede/ECB/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$NoPadding");
- putSymmetricCipherImpl("DESede/ECB/PKCS7Padding",
- PACKAGE_NAME + ".AndroidKeyStore3DESCipherSpi$ECB$PKCS7Padding");
- }
-
- putSymmetricCipherImpl("AES/GCM/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStoreAuthenticatedAESCipherSpi$GCM$NoPadding");
-
- putAsymmetricCipherImpl("RSA/ECB/NoPadding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$NoPadding");
- put("Alg.Alias.Cipher.RSA/None/NoPadding", "RSA/ECB/NoPadding");
- putAsymmetricCipherImpl("RSA/ECB/PKCS1Padding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$PKCS1Padding");
- put("Alg.Alias.Cipher.RSA/None/PKCS1Padding", "RSA/ECB/PKCS1Padding");
- putAsymmetricCipherImpl("RSA/ECB/OAEPPadding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA1AndMGF1Padding");
- put("Alg.Alias.Cipher.RSA/None/OAEPPadding", "RSA/ECB/OAEPPadding");
- putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-1AndMGF1Padding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA1AndMGF1Padding");
- put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-1AndMGF1Padding",
- "RSA/ECB/OAEPWithSHA-1AndMGF1Padding");
- putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-224AndMGF1Padding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA224AndMGF1Padding");
- put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-224AndMGF1Padding",
- "RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
- putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-256AndMGF1Padding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA256AndMGF1Padding");
- put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-256AndMGF1Padding",
- "RSA/ECB/OAEPWithSHA-256AndMGF1Padding");
- putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-384AndMGF1Padding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA384AndMGF1Padding");
- put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-384AndMGF1Padding",
- "RSA/ECB/OAEPWithSHA-384AndMGF1Padding");
- putAsymmetricCipherImpl("RSA/ECB/OAEPWithSHA-512AndMGF1Padding",
- PACKAGE_NAME + ".AndroidKeyStoreRSACipherSpi$OAEPWithSHA512AndMGF1Padding");
- put("Alg.Alias.Cipher.RSA/None/OAEPWithSHA-512AndMGF1Padding",
- "RSA/ECB/OAEPWithSHA-512AndMGF1Padding");
-
- // --------------------- java.security.Signature
- putSignatureImpl("NONEwithRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$NONEWithPKCS1Padding");
-
- putSignatureImpl("MD5withRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$MD5WithPKCS1Padding");
- put("Alg.Alias.Signature.MD5WithRSAEncryption", "MD5withRSA");
- put("Alg.Alias.Signature.MD5/RSA", "MD5withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.4", "MD5withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.2.5with1.2.840.113549.1.1.1", "MD5withRSA");
-
- putSignatureImpl("SHA1withRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA1WithPKCS1Padding");
- put("Alg.Alias.Signature.SHA1WithRSAEncryption", "SHA1withRSA");
- put("Alg.Alias.Signature.SHA1/RSA", "SHA1withRSA");
- put("Alg.Alias.Signature.SHA-1/RSA", "SHA1withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.5", "SHA1withRSA");
- put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.1", "SHA1withRSA");
- put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.113549.1.1.5", "SHA1withRSA");
- put("Alg.Alias.Signature.1.3.14.3.2.29", "SHA1withRSA");
-
- putSignatureImpl("SHA224withRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA224WithPKCS1Padding");
- put("Alg.Alias.Signature.SHA224WithRSAEncryption", "SHA224withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA224withRSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.1",
- "SHA224withRSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.113549.1.1.11",
- "SHA224withRSA");
-
- putSignatureImpl("SHA256withRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA256WithPKCS1Padding");
- put("Alg.Alias.Signature.SHA256WithRSAEncryption", "SHA256withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.11", "SHA256withRSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.1",
- "SHA256withRSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.113549.1.1.11",
- "SHA256withRSA");
-
- putSignatureImpl("SHA384withRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA384WithPKCS1Padding");
- put("Alg.Alias.Signature.SHA384WithRSAEncryption", "SHA384withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.12", "SHA384withRSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.113549.1.1.1",
- "SHA384withRSA");
-
- putSignatureImpl("SHA512withRSA",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA512WithPKCS1Padding");
- put("Alg.Alias.Signature.SHA512WithRSAEncryption", "SHA512withRSA");
- put("Alg.Alias.Signature.1.2.840.113549.1.1.13", "SHA512withRSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.113549.1.1.1",
- "SHA512withRSA");
-
- putSignatureImpl("SHA1withRSA/PSS",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA1WithPSSPadding");
- putSignatureImpl("SHA224withRSA/PSS",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA224WithPSSPadding");
- putSignatureImpl("SHA256withRSA/PSS",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA256WithPSSPadding");
- putSignatureImpl("SHA384withRSA/PSS",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA384WithPSSPadding");
- putSignatureImpl("SHA512withRSA/PSS",
- PACKAGE_NAME + ".AndroidKeyStoreRSASignatureSpi$SHA512WithPSSPadding");
-
- putSignatureImpl("NONEwithECDSA",
- PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$NONE");
-
- putSignatureImpl("SHA1withECDSA", PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA1");
- put("Alg.Alias.Signature.ECDSA", "SHA1withECDSA");
- put("Alg.Alias.Signature.ECDSAwithSHA1", "SHA1withECDSA");
- // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA1(1)
- put("Alg.Alias.Signature.1.2.840.10045.4.1", "SHA1withECDSA");
- put("Alg.Alias.Signature.1.3.14.3.2.26with1.2.840.10045.2.1", "SHA1withECDSA");
-
- // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3)
- putSignatureImpl("SHA224withECDSA",
- PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA224");
- // ecdsa-with-SHA224(1)
- put("Alg.Alias.Signature.1.2.840.10045.4.3.1", "SHA224withECDSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.4with1.2.840.10045.2.1", "SHA224withECDSA");
-
- // iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3)
- putSignatureImpl("SHA256withECDSA",
- PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA256");
- // ecdsa-with-SHA256(2)
- put("Alg.Alias.Signature.1.2.840.10045.4.3.2", "SHA256withECDSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.1with1.2.840.10045.2.1", "SHA256withECDSA");
-
- putSignatureImpl("SHA384withECDSA",
- PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA384");
- // ecdsa-with-SHA384(3)
- put("Alg.Alias.Signature.1.2.840.10045.4.3.3", "SHA384withECDSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.2with1.2.840.10045.2.1", "SHA384withECDSA");
-
- putSignatureImpl("SHA512withECDSA",
- PACKAGE_NAME + ".AndroidKeyStoreECDSASignatureSpi$SHA512");
- // ecdsa-with-SHA512(4)
- put("Alg.Alias.Signature.1.2.840.10045.4.3.4", "SHA512withECDSA");
- put("Alg.Alias.Signature.2.16.840.1.101.3.4.2.3with1.2.840.10045.2.1", "SHA512withECDSA");
- }
-
- private void putMacImpl(String algorithm, String implClass) {
- put("Mac." + algorithm, implClass);
- put("Mac." + algorithm + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
- }
-
- private void putSymmetricCipherImpl(String transformation, String implClass) {
- put("Cipher." + transformation, implClass);
- put("Cipher." + transformation + " SupportedKeyClasses", KEYSTORE_SECRET_KEY_CLASS_NAME);
- }
-
- private void putAsymmetricCipherImpl(String transformation, String implClass) {
- put("Cipher." + transformation, implClass);
- put("Cipher." + transformation + " SupportedKeyClasses",
- KEYSTORE_PRIVATE_KEY_CLASS_NAME + "|" + KEYSTORE_PUBLIC_KEY_CLASS_NAME);
- }
-
- private void putSignatureImpl(String algorithm, String implClass) {
- put("Signature." + algorithm, implClass);
- put("Signature." + algorithm + " SupportedKeyClasses",
- KEYSTORE_PRIVATE_KEY_CLASS_NAME + "|" + KEYSTORE_PUBLIC_KEY_CLASS_NAME);
- }
-
- public static String[] getSupportedEcdsaSignatureDigests() {
- return new String[] {"NONE", "SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512"};
- }
-
- public static String[] getSupportedRsaSignatureWithPkcs1PaddingDigests() {
- return new String[] {"NONE", "MD5", "SHA-1", "SHA-224", "SHA-256", "SHA-384", "SHA-512"};
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
deleted file mode 100644
index ccc3153..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreCipherSpiBase.java
+++ /dev/null
@@ -1,920 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.annotation.CallSuper;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-
-import libcore.util.EmptyArray;
-
-import java.nio.BufferOverflowException;
-import java.nio.ByteBuffer;
-import java.security.AlgorithmParameters;
-import java.security.GeneralSecurityException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.InvalidParameterException;
-import java.security.Key;
-import java.security.KeyFactory;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-
-import javax.crypto.AEADBadTagException;
-import javax.crypto.BadPaddingException;
-import javax.crypto.Cipher;
-import javax.crypto.CipherSpi;
-import javax.crypto.IllegalBlockSizeException;
-import javax.crypto.NoSuchPaddingException;
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactory;
-import javax.crypto.ShortBufferException;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * Base class for {@link CipherSpi} implementations of Android KeyStore backed ciphers.
- *
- * @hide
- */
-abstract class AndroidKeyStoreCipherSpiBase extends CipherSpi implements KeyStoreCryptoOperation {
- private final KeyStore mKeyStore;
-
- // Fields below are populated by Cipher.init and KeyStore.begin and should be preserved after
- // doFinal finishes.
- private boolean mEncrypting;
- private int mKeymasterPurposeOverride = -1;
- private AndroidKeyStoreKey mKey;
- private SecureRandom mRng;
-
- /**
- * Token referencing this operation inside keystore service. It is initialized by
- * {@code engineInit} and is invalidated when {@code engineDoFinal} succeeds and on some error
- * conditions in between.
- */
- private IBinder mOperationToken;
- private long mOperationHandle;
- private KeyStoreCryptoOperationStreamer mMainDataStreamer;
- private KeyStoreCryptoOperationStreamer mAdditionalAuthenticationDataStreamer;
- private boolean mAdditionalAuthenticationDataStreamerClosed;
-
- /**
- * Encountered exception which could not be immediately thrown because it was encountered inside
- * a method that does not throw checked exception. This exception will be thrown from
- * {@code engineDoFinal}. Once such an exception is encountered, {@code engineUpdate} and
- * {@code engineDoFinal} start ignoring input data.
- */
- private Exception mCachedException;
-
- AndroidKeyStoreCipherSpiBase() {
- mKeyStore = KeyStore.getInstance();
- }
-
- @Override
- protected final void engineInit(int opmode, Key key, SecureRandom random)
- throws InvalidKeyException {
- resetAll();
-
- boolean success = false;
- try {
- init(opmode, key, random);
- initAlgorithmSpecificParameters();
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidAlgorithmParameterException e) {
- throw new InvalidKeyException(e);
- }
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- @Override
- protected final void engineInit(int opmode, Key key, AlgorithmParameters params,
- SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
- resetAll();
-
- boolean success = false;
- try {
- init(opmode, key, random);
- initAlgorithmSpecificParameters(params);
- ensureKeystoreOperationInitialized();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- @Override
- protected final void engineInit(int opmode, Key key, AlgorithmParameterSpec params,
- SecureRandom random) throws InvalidKeyException, InvalidAlgorithmParameterException {
- resetAll();
-
- boolean success = false;
- try {
- init(opmode, key, random);
- initAlgorithmSpecificParameters(params);
- ensureKeystoreOperationInitialized();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- private void init(int opmode, Key key, SecureRandom random) throws InvalidKeyException {
- switch (opmode) {
- case Cipher.ENCRYPT_MODE:
- case Cipher.WRAP_MODE:
- mEncrypting = true;
- break;
- case Cipher.DECRYPT_MODE:
- case Cipher.UNWRAP_MODE:
- mEncrypting = false;
- break;
- default:
- throw new InvalidParameterException("Unsupported opmode: " + opmode);
- }
- initKey(opmode, key);
- if (mKey == null) {
- throw new ProviderException("initKey did not initialize the key");
- }
- mRng = random;
- }
-
- /**
- * Resets this cipher to its pristine pre-init state. This must be equivalent to obtaining a new
- * cipher instance.
- *
- * <p>Subclasses storing additional state should override this method, reset the additional
- * state, and then chain to superclass.
- */
- @CallSuper
- protected void resetAll() {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mKeyStore.abort(operationToken);
- }
- mEncrypting = false;
- mKeymasterPurposeOverride = -1;
- mKey = null;
- mRng = null;
- mOperationToken = null;
- mOperationHandle = 0;
- mMainDataStreamer = null;
- mAdditionalAuthenticationDataStreamer = null;
- mAdditionalAuthenticationDataStreamerClosed = false;
- mCachedException = null;
- }
-
- /**
- * Resets this cipher while preserving the initialized state. This must be equivalent to
- * rolling back the cipher's state to just after the most recent {@code engineInit} completed
- * successfully.
- *
- * <p>Subclasses storing additional post-init state should override this method, reset the
- * additional state, and then chain to superclass.
- */
- @CallSuper
- protected void resetWhilePreservingInitState() {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mKeyStore.abort(operationToken);
- }
- mOperationToken = null;
- mOperationHandle = 0;
- mMainDataStreamer = null;
- mAdditionalAuthenticationDataStreamer = null;
- mAdditionalAuthenticationDataStreamerClosed = false;
- mCachedException = null;
- }
-
- private void ensureKeystoreOperationInitialized() throws InvalidKeyException,
- InvalidAlgorithmParameterException {
- if (mMainDataStreamer != null) {
- return;
- }
- if (mCachedException != null) {
- return;
- }
- if (mKey == null) {
- throw new IllegalStateException("Not initialized");
- }
-
- KeymasterArguments keymasterInputArgs = new KeymasterArguments();
- addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
- byte[] additionalEntropy = KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- mRng, getAdditionalEntropyAmountForBegin());
-
- int purpose;
- if (mKeymasterPurposeOverride != -1) {
- purpose = mKeymasterPurposeOverride;
- } else {
- purpose = mEncrypting
- ? KeymasterDefs.KM_PURPOSE_ENCRYPT : KeymasterDefs.KM_PURPOSE_DECRYPT;
- }
- OperationResult opResult = mKeyStore.begin(
- mKey.getAlias(),
- purpose,
- true, // permit aborting this operation if keystore runs out of resources
- keymasterInputArgs,
- additionalEntropy,
- mKey.getUid());
- if (opResult == null) {
- throw new KeyStoreConnectException();
- }
-
- // Store operation token and handle regardless of the error code returned by KeyStore to
- // ensure that the operation gets aborted immediately if the code below throws an exception.
- mOperationToken = opResult.token;
- mOperationHandle = opResult.operationHandle;
-
- // If necessary, throw an exception due to KeyStore operation having failed.
- GeneralSecurityException e = KeyStoreCryptoOperationUtils.getExceptionForCipherInit(
- mKeyStore, mKey, opResult.resultCode);
- if (e != null) {
- if (e instanceof InvalidKeyException) {
- throw (InvalidKeyException) e;
- } else if (e instanceof InvalidAlgorithmParameterException) {
- throw (InvalidAlgorithmParameterException) e;
- } else {
- throw new ProviderException("Unexpected exception type", e);
- }
- }
-
- if (mOperationToken == null) {
- throw new ProviderException("Keystore returned null operation token");
- }
- if (mOperationHandle == 0) {
- throw new ProviderException("Keystore returned invalid operation handle");
- }
-
- loadAlgorithmSpecificParametersFromBeginResult(opResult.outParams);
- mMainDataStreamer = createMainDataStreamer(mKeyStore, opResult.token);
- mAdditionalAuthenticationDataStreamer =
- createAdditionalAuthenticationDataStreamer(mKeyStore, opResult.token);
- mAdditionalAuthenticationDataStreamerClosed = false;
- }
-
- /**
- * Creates a streamer which sends plaintext/ciphertext into the provided KeyStore and receives
- * the corresponding ciphertext/plaintext from the KeyStore.
- *
- * <p>This implementation returns a working streamer.
- */
- @NonNull
- protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
- KeyStore keyStore, IBinder operationToken) {
- return new KeyStoreCryptoOperationChunkedStreamer(
- new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
- keyStore, operationToken), 0);
- }
-
- /**
- * Creates a streamer which sends Additional Authentication Data (AAD) into the KeyStore.
- *
- * <p>This implementation returns {@code null}.
- *
- * @return stream or {@code null} if AAD is not supported by this cipher.
- */
- @Nullable
- protected KeyStoreCryptoOperationStreamer createAdditionalAuthenticationDataStreamer(
- @SuppressWarnings("unused") KeyStore keyStore,
- @SuppressWarnings("unused") IBinder operationToken) {
- return null;
- }
-
- @Override
- protected final byte[] engineUpdate(byte[] input, int inputOffset, int inputLen) {
- if (mCachedException != null) {
- return null;
- }
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
- mCachedException = e;
- return null;
- }
-
- if (inputLen == 0) {
- return null;
- }
-
- byte[] output;
- try {
- flushAAD();
- output = mMainDataStreamer.update(input, inputOffset, inputLen);
- } catch (KeyStoreException e) {
- mCachedException = e;
- return null;
- }
-
- if (output.length == 0) {
- return null;
- }
-
- return output;
- }
-
- private void flushAAD() throws KeyStoreException {
- if ((mAdditionalAuthenticationDataStreamer != null)
- && (!mAdditionalAuthenticationDataStreamerClosed)) {
- byte[] output;
- try {
- output = mAdditionalAuthenticationDataStreamer.doFinal(
- EmptyArray.BYTE, 0, 0,
- null, // no signature
- null // no additional entropy needed flushing AAD
- );
- } finally {
- mAdditionalAuthenticationDataStreamerClosed = true;
- }
- if ((output != null) && (output.length > 0)) {
- throw new ProviderException(
- "AAD update unexpectedly returned data: " + output.length + " bytes");
- }
- }
- }
-
- @Override
- protected final int engineUpdate(byte[] input, int inputOffset, int inputLen, byte[] output,
- int outputOffset) throws ShortBufferException {
- byte[] outputCopy = engineUpdate(input, inputOffset, inputLen);
- if (outputCopy == null) {
- return 0;
- }
- int outputAvailable = output.length - outputOffset;
- if (outputCopy.length > outputAvailable) {
- throw new ShortBufferException("Output buffer too short. Produced: "
- + outputCopy.length + ", available: " + outputAvailable);
- }
- System.arraycopy(outputCopy, 0, output, outputOffset, outputCopy.length);
- return outputCopy.length;
- }
-
- @Override
- protected final int engineUpdate(ByteBuffer input, ByteBuffer output)
- throws ShortBufferException {
- if (input == null) {
- throw new NullPointerException("input == null");
- }
- if (output == null) {
- throw new NullPointerException("output == null");
- }
-
- int inputSize = input.remaining();
- byte[] outputArray;
- if (input.hasArray()) {
- outputArray =
- engineUpdate(
- input.array(), input.arrayOffset() + input.position(), inputSize);
- input.position(input.position() + inputSize);
- } else {
- byte[] inputArray = new byte[inputSize];
- input.get(inputArray);
- outputArray = engineUpdate(inputArray, 0, inputSize);
- }
-
- int outputSize = (outputArray != null) ? outputArray.length : 0;
- if (outputSize > 0) {
- int outputBufferAvailable = output.remaining();
- try {
- output.put(outputArray);
- } catch (BufferOverflowException e) {
- throw new ShortBufferException(
- "Output buffer too small. Produced: " + outputSize + ", available: "
- + outputBufferAvailable);
- }
- }
- return outputSize;
- }
-
- @Override
- protected final void engineUpdateAAD(byte[] input, int inputOffset, int inputLen) {
- if (mCachedException != null) {
- return;
- }
-
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
- mCachedException = e;
- return;
- }
-
- if (mAdditionalAuthenticationDataStreamerClosed) {
- throw new IllegalStateException(
- "AAD can only be provided before Cipher.update is invoked");
- }
-
- if (mAdditionalAuthenticationDataStreamer == null) {
- throw new IllegalStateException("This cipher does not support AAD");
- }
-
- byte[] output;
- try {
- output = mAdditionalAuthenticationDataStreamer.update(input, inputOffset, inputLen);
- } catch (KeyStoreException e) {
- mCachedException = e;
- return;
- }
-
- if ((output != null) && (output.length > 0)) {
- throw new ProviderException("AAD update unexpectedly produced output: "
- + output.length + " bytes");
- }
- }
-
- @Override
- protected final void engineUpdateAAD(ByteBuffer src) {
- if (src == null) {
- throw new IllegalArgumentException("src == null");
- }
- if (!src.hasRemaining()) {
- return;
- }
-
- byte[] input;
- int inputOffset;
- int inputLen;
- if (src.hasArray()) {
- input = src.array();
- inputOffset = src.arrayOffset() + src.position();
- inputLen = src.remaining();
- src.position(src.limit());
- } else {
- input = new byte[src.remaining()];
- inputOffset = 0;
- inputLen = input.length;
- src.get(input);
- }
- engineUpdateAAD(input, inputOffset, inputLen);
- }
-
- @Override
- protected final byte[] engineDoFinal(byte[] input, int inputOffset, int inputLen)
- throws IllegalBlockSizeException, BadPaddingException {
- if (mCachedException != null) {
- throw (IllegalBlockSizeException)
- new IllegalBlockSizeException().initCause(mCachedException);
- }
-
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException | InvalidAlgorithmParameterException e) {
- throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
- }
-
- byte[] output;
- try {
- flushAAD();
- byte[] additionalEntropy =
- KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- mRng, getAdditionalEntropyAmountForFinish());
- output = mMainDataStreamer.doFinal(
- input, inputOffset, inputLen,
- null, // no signature involved
- additionalEntropy);
- } catch (KeyStoreException e) {
- switch (e.getErrorCode()) {
- case KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH:
- throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
- case KeymasterDefs.KM_ERROR_INVALID_ARGUMENT:
- throw (BadPaddingException) new BadPaddingException().initCause(e);
- case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
- throw (AEADBadTagException) new AEADBadTagException().initCause(e);
- default:
- throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
- }
- }
-
- resetWhilePreservingInitState();
- return output;
- }
-
- @Override
- protected final int engineDoFinal(byte[] input, int inputOffset, int inputLen, byte[] output,
- int outputOffset) throws ShortBufferException, IllegalBlockSizeException,
- BadPaddingException {
- byte[] outputCopy = engineDoFinal(input, inputOffset, inputLen);
- if (outputCopy == null) {
- return 0;
- }
- int outputAvailable = output.length - outputOffset;
- if (outputCopy.length > outputAvailable) {
- throw new ShortBufferException("Output buffer too short. Produced: "
- + outputCopy.length + ", available: " + outputAvailable);
- }
- System.arraycopy(outputCopy, 0, output, outputOffset, outputCopy.length);
- return outputCopy.length;
- }
-
- @Override
- protected final int engineDoFinal(ByteBuffer input, ByteBuffer output)
- throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
- if (input == null) {
- throw new NullPointerException("input == null");
- }
- if (output == null) {
- throw new NullPointerException("output == null");
- }
-
- int inputSize = input.remaining();
- byte[] outputArray;
- if (input.hasArray()) {
- outputArray =
- engineDoFinal(
- input.array(), input.arrayOffset() + input.position(), inputSize);
- input.position(input.position() + inputSize);
- } else {
- byte[] inputArray = new byte[inputSize];
- input.get(inputArray);
- outputArray = engineDoFinal(inputArray, 0, inputSize);
- }
-
- int outputSize = (outputArray != null) ? outputArray.length : 0;
- if (outputSize > 0) {
- int outputBufferAvailable = output.remaining();
- try {
- output.put(outputArray);
- } catch (BufferOverflowException e) {
- throw new ShortBufferException(
- "Output buffer too small. Produced: " + outputSize + ", available: "
- + outputBufferAvailable);
- }
- }
- return outputSize;
- }
-
- @Override
- protected final byte[] engineWrap(Key key)
- throws IllegalBlockSizeException, InvalidKeyException {
- if (mKey == null) {
- throw new IllegalStateException("Not initilized");
- }
-
- if (!isEncrypting()) {
- throw new IllegalStateException(
- "Cipher must be initialized in Cipher.WRAP_MODE to wrap keys");
- }
-
- if (key == null) {
- throw new NullPointerException("key == null");
- }
- byte[] encoded = null;
- if (key instanceof SecretKey) {
- if ("RAW".equalsIgnoreCase(key.getFormat())) {
- encoded = key.getEncoded();
- }
- if (encoded == null) {
- try {
- SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(key.getAlgorithm());
- SecretKeySpec spec =
- (SecretKeySpec) keyFactory.getKeySpec(
- (SecretKey) key, SecretKeySpec.class);
- encoded = spec.getEncoded();
- } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
- throw new InvalidKeyException(
- "Failed to wrap key because it does not export its key material",
- e);
- }
- }
- } else if (key instanceof PrivateKey) {
- if ("PKCS8".equalsIgnoreCase(key.getFormat())) {
- encoded = key.getEncoded();
- }
- if (encoded == null) {
- try {
- KeyFactory keyFactory = KeyFactory.getInstance(key.getAlgorithm());
- PKCS8EncodedKeySpec spec =
- keyFactory.getKeySpec(key, PKCS8EncodedKeySpec.class);
- encoded = spec.getEncoded();
- } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
- throw new InvalidKeyException(
- "Failed to wrap key because it does not export its key material",
- e);
- }
- }
- } else if (key instanceof PublicKey) {
- if ("X.509".equalsIgnoreCase(key.getFormat())) {
- encoded = key.getEncoded();
- }
- if (encoded == null) {
- try {
- KeyFactory keyFactory = KeyFactory.getInstance(key.getAlgorithm());
- X509EncodedKeySpec spec =
- keyFactory.getKeySpec(key, X509EncodedKeySpec.class);
- encoded = spec.getEncoded();
- } catch (NoSuchAlgorithmException | InvalidKeySpecException e) {
- throw new InvalidKeyException(
- "Failed to wrap key because it does not export its key material",
- e);
- }
- }
- } else {
- throw new InvalidKeyException("Unsupported key type: " + key.getClass().getName());
- }
-
- if (encoded == null) {
- throw new InvalidKeyException(
- "Failed to wrap key because it does not export its key material");
- }
-
- try {
- return engineDoFinal(encoded, 0, encoded.length);
- } catch (BadPaddingException e) {
- throw (IllegalBlockSizeException) new IllegalBlockSizeException().initCause(e);
- }
- }
-
- @Override
- protected final Key engineUnwrap(byte[] wrappedKey, String wrappedKeyAlgorithm,
- int wrappedKeyType) throws InvalidKeyException, NoSuchAlgorithmException {
- if (mKey == null) {
- throw new IllegalStateException("Not initilized");
- }
-
- if (isEncrypting()) {
- throw new IllegalStateException(
- "Cipher must be initialized in Cipher.WRAP_MODE to wrap keys");
- }
-
- if (wrappedKey == null) {
- throw new NullPointerException("wrappedKey == null");
- }
-
- byte[] encoded;
- try {
- encoded = engineDoFinal(wrappedKey, 0, wrappedKey.length);
- } catch (IllegalBlockSizeException | BadPaddingException e) {
- throw new InvalidKeyException("Failed to unwrap key", e);
- }
-
- switch (wrappedKeyType) {
- case Cipher.SECRET_KEY:
- {
- return new SecretKeySpec(encoded, wrappedKeyAlgorithm);
- // break;
- }
- case Cipher.PRIVATE_KEY:
- {
- KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
- try {
- return keyFactory.generatePrivate(new PKCS8EncodedKeySpec(encoded));
- } catch (InvalidKeySpecException e) {
- throw new InvalidKeyException(
- "Failed to create private key from its PKCS#8 encoded form", e);
- }
- // break;
- }
- case Cipher.PUBLIC_KEY:
- {
- KeyFactory keyFactory = KeyFactory.getInstance(wrappedKeyAlgorithm);
- try {
- return keyFactory.generatePublic(new X509EncodedKeySpec(encoded));
- } catch (InvalidKeySpecException e) {
- throw new InvalidKeyException(
- "Failed to create public key from its X.509 encoded form", e);
- }
- // break;
- }
- default:
- throw new InvalidParameterException(
- "Unsupported wrappedKeyType: " + wrappedKeyType);
- }
- }
-
- @Override
- protected final void engineSetMode(String mode) throws NoSuchAlgorithmException {
- // This should never be invoked because all algorithms registered with the AndroidKeyStore
- // provide explicitly specify block mode.
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected final void engineSetPadding(String arg0) throws NoSuchPaddingException {
- // This should never be invoked because all algorithms registered with the AndroidKeyStore
- // provide explicitly specify padding mode.
- throw new UnsupportedOperationException();
- }
-
- @Override
- protected final int engineGetKeySize(Key key) throws InvalidKeyException {
- throw new UnsupportedOperationException();
- }
-
- @CallSuper
- @Override
- public void finalize() throws Throwable {
- try {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mKeyStore.abort(operationToken);
- }
- } finally {
- super.finalize();
- }
- }
-
- @Override
- public final long getOperationHandle() {
- return mOperationHandle;
- }
-
- protected final void setKey(@NonNull AndroidKeyStoreKey key) {
- mKey = key;
- }
-
- /**
- * Overrides the default purpose/type of the crypto operation.
- */
- protected final void setKeymasterPurposeOverride(int keymasterPurpose) {
- mKeymasterPurposeOverride = keymasterPurpose;
- }
-
- protected final int getKeymasterPurposeOverride() {
- return mKeymasterPurposeOverride;
- }
-
- /**
- * Returns {@code true} if this cipher is initialized for encryption, {@code false} if this
- * cipher is initialized for decryption.
- */
- protected final boolean isEncrypting() {
- return mEncrypting;
- }
-
- @NonNull
- protected final KeyStore getKeyStore() {
- return mKeyStore;
- }
-
- protected final long getConsumedInputSizeBytes() {
- if (mMainDataStreamer == null) {
- throw new IllegalStateException("Not initialized");
- }
- return mMainDataStreamer.getConsumedInputSizeBytes();
- }
-
- protected final long getProducedOutputSizeBytes() {
- if (mMainDataStreamer == null) {
- throw new IllegalStateException("Not initialized");
- }
- return mMainDataStreamer.getProducedOutputSizeBytes();
- }
-
- static String opmodeToString(int opmode) {
- switch (opmode) {
- case Cipher.ENCRYPT_MODE:
- return "ENCRYPT_MODE";
- case Cipher.DECRYPT_MODE:
- return "DECRYPT_MODE";
- case Cipher.WRAP_MODE:
- return "WRAP_MODE";
- case Cipher.UNWRAP_MODE:
- return "UNWRAP_MODE";
- default:
- return String.valueOf(opmode);
- }
- }
-
- // The methods below need to be implemented by subclasses.
-
- /**
- * Initializes this cipher with the provided key.
- *
- * @throws InvalidKeyException if the {@code key} is not suitable for this cipher in the
- * specified {@code opmode}.
- *
- * @see #setKey(AndroidKeyStoreKey)
- */
- protected abstract void initKey(int opmode, @Nullable Key key) throws InvalidKeyException;
-
- /**
- * Returns algorithm-specific parameters used by this cipher or {@code null} if no
- * algorithm-specific parameters are used.
- */
- @Nullable
- @Override
- protected abstract AlgorithmParameters engineGetParameters();
-
- /**
- * Invoked by {@code engineInit} to initialize algorithm-specific parameters when no additional
- * initialization parameters were provided.
- *
- * @throws InvalidKeyException if this cipher cannot be configured based purely on the provided
- * key and needs additional parameters to be provided to {@code Cipher.init}.
- */
- protected abstract void initAlgorithmSpecificParameters() throws InvalidKeyException;
-
- /**
- * Invoked by {@code engineInit} to initialize algorithm-specific parameters when additional
- * parameters were provided.
- *
- * @param params additional algorithm parameters or {@code null} if not specified.
- *
- * @throws InvalidAlgorithmParameterException if there is insufficient information to configure
- * this cipher or if the provided parameters are not suitable for this cipher.
- */
- protected abstract void initAlgorithmSpecificParameters(
- @Nullable AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException;
-
- /**
- * Invoked by {@code engineInit} to initialize algorithm-specific parameters when additional
- * parameters were provided.
- *
- * @param params additional algorithm parameters or {@code null} if not specified.
- *
- * @throws InvalidAlgorithmParameterException if there is insufficient information to configure
- * this cipher or if the provided parameters are not suitable for this cipher.
- */
- protected abstract void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params)
- throws InvalidAlgorithmParameterException;
-
- /**
- * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
- * {@code begin} operation. This amount of entropy is typically what's consumed to generate
- * random parameters, such as IV.
- *
- * <p>For decryption, the return value should be {@code 0} because decryption should not be
- * consuming any entropy. For encryption, the value combined with
- * {@link #getAdditionalEntropyAmountForFinish()} should match (or exceed) the amount of Shannon
- * entropy of the ciphertext produced by this cipher assuming the key, the plaintext, and all
- * explicitly provided parameters to {@code Cipher.init} are known. For example, for AES CBC
- * encryption with an explicitly provided IV the return value should be {@code 0}, whereas for
- * the case where IV is generated by the KeyStore's {@code begin} operation it should be
- * {@code 16}.
- */
- protected abstract int getAdditionalEntropyAmountForBegin();
-
- /**
- * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
- * {@code finish} operation. This amount of entropy is typically what's consumed by encryption
- * padding scheme.
- *
- * <p>For decryption, the return value should be {@code 0} because decryption should not be
- * consuming any entropy. For encryption, the value combined with
- * {@link #getAdditionalEntropyAmountForBegin()} should match (or exceed) the amount of Shannon
- * entropy of the ciphertext produced by this cipher assuming the key, the plaintext, and all
- * explicitly provided parameters to {@code Cipher.init} are known. For example, for RSA with
- * OAEP the return value should be the size of the OAEP hash output. For RSA with PKCS#1 padding
- * the return value should be the size of the padding string or could be raised (for simplicity)
- * to the size of the modulus.
- */
- protected abstract int getAdditionalEntropyAmountForFinish();
-
- /**
- * Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation.
- *
- * @param keymasterArgs keystore/keymaster arguments to be populated with algorithm-specific
- * parameters.
- */
- protected abstract void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs);
-
- /**
- * Invoked to obtain algorithm-specific parameters from the result of the KeyStore's
- * {@code begin} operation.
- *
- * <p>Some parameters, such as IV, are not required to be provided to {@code Cipher.init}. Such
- * parameters, if not provided, must be generated by KeyStore and returned to the user of
- * {@code Cipher} and potentially reused after {@code doFinal}.
- *
- * @param keymasterArgs keystore/keymaster arguments returned by KeyStore {@code begin}
- * operation.
- */
- protected abstract void loadAlgorithmSpecificParametersFromBeginResult(
- @NonNull KeymasterArguments keymasterArgs);
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
deleted file mode 100644
index 45f2110..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECDSASignatureSpi.java
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.annotation.NonNull;
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayOutputStream;
-import java.security.InvalidKeyException;
-import java.security.SignatureSpi;
-
-/**
- * Base class for {@link SignatureSpi} providing Android KeyStore backed ECDSA signatures.
- *
- * @hide
- */
-abstract class AndroidKeyStoreECDSASignatureSpi extends AndroidKeyStoreSignatureSpiBase {
-
- public final static class NONE extends AndroidKeyStoreECDSASignatureSpi {
- public NONE() {
- super(KeymasterDefs.KM_DIGEST_NONE);
- }
-
- @Override
- protected KeyStoreCryptoOperationStreamer createMainDataStreamer(KeyStore keyStore,
- IBinder operationToken) {
- return new TruncateToFieldSizeMessageStreamer(
- super.createMainDataStreamer(keyStore, operationToken),
- getGroupSizeBits());
- }
-
- /**
- * Streamer which buffers all input, then truncates it to field size, and then sends it into
- * KeyStore via the provided delegate streamer.
- */
- private static class TruncateToFieldSizeMessageStreamer
- implements KeyStoreCryptoOperationStreamer {
-
- private final KeyStoreCryptoOperationStreamer mDelegate;
- private final int mGroupSizeBits;
- private final ByteArrayOutputStream mInputBuffer = new ByteArrayOutputStream();
- private long mConsumedInputSizeBytes;
-
- private TruncateToFieldSizeMessageStreamer(
- KeyStoreCryptoOperationStreamer delegate,
- int groupSizeBits) {
- mDelegate = delegate;
- mGroupSizeBits = groupSizeBits;
- }
-
- @Override
- public byte[] update(byte[] input, int inputOffset, int inputLength)
- throws KeyStoreException {
- if (inputLength > 0) {
- mInputBuffer.write(input, inputOffset, inputLength);
- mConsumedInputSizeBytes += inputLength;
- }
- return EmptyArray.BYTE;
- }
-
- @Override
- public byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] signature,
- byte[] additionalEntropy) throws KeyStoreException {
- if (inputLength > 0) {
- mConsumedInputSizeBytes += inputLength;
- mInputBuffer.write(input, inputOffset, inputLength);
- }
-
- byte[] bufferedInput = mInputBuffer.toByteArray();
- mInputBuffer.reset();
- // Truncate input at field size (bytes)
- return mDelegate.doFinal(bufferedInput,
- 0,
- Math.min(bufferedInput.length, ((mGroupSizeBits + 7) / 8)),
- signature, additionalEntropy);
- }
-
- @Override
- public long getConsumedInputSizeBytes() {
- return mConsumedInputSizeBytes;
- }
-
- @Override
- public long getProducedOutputSizeBytes() {
- return mDelegate.getProducedOutputSizeBytes();
- }
- }
- }
-
- public final static class SHA1 extends AndroidKeyStoreECDSASignatureSpi {
- public SHA1() {
- super(KeymasterDefs.KM_DIGEST_SHA1);
- }
- }
-
- public final static class SHA224 extends AndroidKeyStoreECDSASignatureSpi {
- public SHA224() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_224);
- }
- }
-
- public final static class SHA256 extends AndroidKeyStoreECDSASignatureSpi {
- public SHA256() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_256);
- }
- }
-
- public final static class SHA384 extends AndroidKeyStoreECDSASignatureSpi {
- public SHA384() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_384);
- }
- }
-
- public final static class SHA512 extends AndroidKeyStoreECDSASignatureSpi {
- public SHA512() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- private final int mKeymasterDigest;
-
- private int mGroupSizeBits = -1;
-
- AndroidKeyStoreECDSASignatureSpi(int keymasterDigest) {
- mKeymasterDigest = keymasterDigest;
- }
-
- @Override
- protected final void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
- if (!KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(key.getAlgorithm())) {
- throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm()
- + ". Only" + KeyProperties.KEY_ALGORITHM_EC + " supported");
- }
-
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- int errorCode = getKeyStore().getKeyCharacteristics(
- key.getAlias(), null, null, key.getUid(), keyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- throw getKeyStore().getInvalidKeyException(key.getAlias(), key.getUid(), errorCode);
- }
- long keySizeBits = keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
- if (keySizeBits == -1) {
- throw new InvalidKeyException("Size of key not known");
- } else if (keySizeBits > Integer.MAX_VALUE) {
- throw new InvalidKeyException("Key too large: " + keySizeBits + " bits");
- }
- mGroupSizeBits = (int) keySizeBits;
-
- super.initKey(key);
- }
-
- @Override
- protected final void resetAll() {
- mGroupSizeBits = -1;
- super.resetAll();
- }
-
- @Override
- protected final void resetWhilePreservingInitState() {
- super.resetWhilePreservingInitState();
- }
-
- @Override
- protected final void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs) {
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_EC);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForSign() {
- return (mGroupSizeBits + 7) / 8;
- }
-
- protected final int getGroupSizeBits() {
- if (mGroupSizeBits == -1) {
- throw new IllegalStateException("Not initialized");
- }
- return mGroupSizeBits;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
deleted file mode 100644
index aa7bdff..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECPrivateKey.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import java.security.PrivateKey;
-import java.security.interfaces.ECKey;
-import java.security.spec.ECParameterSpec;
-
-/**
- * EC private key (instance of {@link PrivateKey} and {@link ECKey}) backed by keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreECPrivateKey extends AndroidKeyStorePrivateKey implements ECKey {
- private final ECParameterSpec mParams;
-
- public AndroidKeyStoreECPrivateKey(String alias, int uid, ECParameterSpec params) {
- super(alias, uid, KeyProperties.KEY_ALGORITHM_EC);
- mParams = params;
- }
-
- @Override
- public ECParameterSpec getParams() {
- return mParams;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java
deleted file mode 100644
index 2efaeb6..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreECPublicKey.java
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import java.security.interfaces.ECPublicKey;
-import java.security.spec.ECParameterSpec;
-import java.security.spec.ECPoint;
-
-/**
- * {@link ECPublicKey} backed by keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreECPublicKey extends AndroidKeyStorePublicKey implements ECPublicKey {
-
- private final ECParameterSpec mParams;
- private final ECPoint mW;
-
- public AndroidKeyStoreECPublicKey(String alias, int uid, byte[] x509EncodedForm, ECParameterSpec params,
- ECPoint w) {
- super(alias, uid, KeyProperties.KEY_ALGORITHM_EC, x509EncodedForm);
- mParams = params;
- mW = w;
- }
-
- public AndroidKeyStoreECPublicKey(String alias, int uid, ECPublicKey info) {
- this(alias, uid, info.getEncoded(), info.getParams(), info.getW());
- if (!"X.509".equalsIgnoreCase(info.getFormat())) {
- throw new IllegalArgumentException(
- "Unsupported key export format: " + info.getFormat());
- }
- }
-
- @Override
- public ECParameterSpec getParams() {
- return mParams;
- }
-
- @Override
- public ECPoint getW() {
- return mW;
- }
-}
\ No newline at end of file
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
deleted file mode 100644
index 2e8ac32..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreHmacSpi.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-
-import javax.crypto.MacSpi;
-
-/**
- * {@link MacSpi} which provides HMAC implementations backed by Android KeyStore.
- *
- * @hide
- */
-public abstract class AndroidKeyStoreHmacSpi extends MacSpi implements KeyStoreCryptoOperation {
-
- public static class HmacSHA1 extends AndroidKeyStoreHmacSpi {
- public HmacSHA1() {
- super(KeymasterDefs.KM_DIGEST_SHA1);
- }
- }
-
- public static class HmacSHA224 extends AndroidKeyStoreHmacSpi {
- public HmacSHA224() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_224);
- }
- }
-
- public static class HmacSHA256 extends AndroidKeyStoreHmacSpi {
- public HmacSHA256() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_256);
- }
- }
-
- public static class HmacSHA384 extends AndroidKeyStoreHmacSpi {
- public HmacSHA384() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_384);
- }
- }
-
- public static class HmacSHA512 extends AndroidKeyStoreHmacSpi {
- public HmacSHA512() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- private final KeyStore mKeyStore = KeyStore.getInstance();
- private final int mKeymasterDigest;
- private final int mMacSizeBits;
-
- // Fields below are populated by engineInit and should be preserved after engineDoFinal.
- private AndroidKeyStoreSecretKey mKey;
-
- // Fields below are reset when engineDoFinal succeeds.
- private KeyStoreCryptoOperationChunkedStreamer mChunkedStreamer;
- private IBinder mOperationToken;
- private long mOperationHandle;
-
- protected AndroidKeyStoreHmacSpi(int keymasterDigest) {
- mKeymasterDigest = keymasterDigest;
- mMacSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
- }
-
- @Override
- protected int engineGetMacLength() {
- return (mMacSizeBits + 7) / 8;
- }
-
- @Override
- protected void engineInit(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
- InvalidAlgorithmParameterException {
- resetAll();
-
- boolean success = false;
- try {
- init(key, params);
- ensureKeystoreOperationInitialized();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- private void init(Key key, AlgorithmParameterSpec params) throws InvalidKeyException,
- InvalidAlgorithmParameterException {
- if (key == null) {
- throw new InvalidKeyException("key == null");
- } else if (!(key instanceof AndroidKeyStoreSecretKey)) {
- throw new InvalidKeyException(
- "Only Android KeyStore secret keys supported. Key: " + key);
- }
- mKey = (AndroidKeyStoreSecretKey) key;
-
- if (params != null) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported algorithm parameters: " + params);
- }
-
- }
-
- private void resetAll() {
- mKey = null;
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mKeyStore.abort(operationToken);
- }
- mOperationToken = null;
- mOperationHandle = 0;
- mChunkedStreamer = null;
- }
-
- private void resetWhilePreservingInitState() {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mKeyStore.abort(operationToken);
- }
- mOperationToken = null;
- mOperationHandle = 0;
- mChunkedStreamer = null;
- }
-
- @Override
- protected void engineReset() {
- resetWhilePreservingInitState();
- }
-
- private void ensureKeystoreOperationInitialized() throws InvalidKeyException {
- if (mChunkedStreamer != null) {
- return;
- }
- if (mKey == null) {
- throw new IllegalStateException("Not initialized");
- }
-
- KeymasterArguments keymasterArgs = new KeymasterArguments();
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_HMAC);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
- keymasterArgs.addUnsignedInt(KeymasterDefs.KM_TAG_MAC_LENGTH, mMacSizeBits);
-
- OperationResult opResult = mKeyStore.begin(
- mKey.getAlias(),
- KeymasterDefs.KM_PURPOSE_SIGN,
- true,
- keymasterArgs,
- null, // no additional entropy needed for HMAC because it's deterministic
- mKey.getUid());
-
- if (opResult == null) {
- throw new KeyStoreConnectException();
- }
-
- // Store operation token and handle regardless of the error code returned by KeyStore to
- // ensure that the operation gets aborted immediately if the code below throws an exception.
- mOperationToken = opResult.token;
- mOperationHandle = opResult.operationHandle;
-
- // If necessary, throw an exception due to KeyStore operation having failed.
- InvalidKeyException e = KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(
- mKeyStore, mKey, opResult.resultCode);
- if (e != null) {
- throw e;
- }
-
- if (mOperationToken == null) {
- throw new ProviderException("Keystore returned null operation token");
- }
- if (mOperationHandle == 0) {
- throw new ProviderException("Keystore returned invalid operation handle");
- }
-
- mChunkedStreamer = new KeyStoreCryptoOperationChunkedStreamer(
- new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
- mKeyStore, mOperationToken));
- }
-
- @Override
- protected void engineUpdate(byte input) {
- engineUpdate(new byte[] {input}, 0, 1);
- }
-
- @Override
- protected void engineUpdate(byte[] input, int offset, int len) {
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException e) {
- throw new ProviderException("Failed to reinitialize MAC", e);
- }
-
- byte[] output;
- try {
- output = mChunkedStreamer.update(input, offset, len);
- } catch (KeyStoreException e) {
- throw new ProviderException("Keystore operation failed", e);
- }
- if ((output != null) && (output.length != 0)) {
- throw new ProviderException("Update operation unexpectedly produced output");
- }
- }
-
- @Override
- protected byte[] engineDoFinal() {
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException e) {
- throw new ProviderException("Failed to reinitialize MAC", e);
- }
-
- byte[] result;
- try {
- result = mChunkedStreamer.doFinal(
- null, 0, 0,
- null, // no signature provided -- this invocation will generate one
- null // no additional entropy needed -- HMAC is deterministic
- );
- } catch (KeyStoreException e) {
- throw new ProviderException("Keystore operation failed", e);
- }
-
- resetWhilePreservingInitState();
- return result;
- }
-
- @Override
- public void finalize() throws Throwable {
- try {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mKeyStore.abort(operationToken);
- }
- } finally {
- super.finalize();
- }
- }
-
- @Override
- public long getOperationHandle() {
- return mOperationHandle;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
deleted file mode 100644
index e8e6310..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKey.java
+++ /dev/null
@@ -1,103 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import java.security.Key;
-
-/**
- * {@link Key} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreKey implements Key {
- private final String mAlias;
- private final int mUid;
- private final String mAlgorithm;
-
- public AndroidKeyStoreKey(String alias, int uid, String algorithm) {
- mAlias = alias;
- mUid = uid;
- mAlgorithm = algorithm;
- }
-
- String getAlias() {
- return mAlias;
- }
-
- int getUid() {
- return mUid;
- }
-
- @Override
- public String getAlgorithm() {
- return mAlgorithm;
- }
-
- @Override
- public String getFormat() {
- // This key does not export its key material
- return null;
- }
-
- @Override
- public byte[] getEncoded() {
- // This key does not export its key material
- return null;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + ((mAlgorithm == null) ? 0 : mAlgorithm.hashCode());
- result = prime * result + ((mAlias == null) ? 0 : mAlias.hashCode());
- result = prime * result + mUid;
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (obj == null) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- AndroidKeyStoreKey other = (AndroidKeyStoreKey) obj;
- if (mAlgorithm == null) {
- if (other.mAlgorithm != null) {
- return false;
- }
- } else if (!mAlgorithm.equals(other.mAlgorithm)) {
- return false;
- }
- if (mAlias == null) {
- if (other.mAlias != null) {
- return false;
- }
- } else if (!mAlias.equals(other.mAlias)) {
- return false;
- }
- if (mUid != other.mUid) {
- return false;
- }
- return true;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
deleted file mode 100644
index 303b0f2..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyFactorySpi.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.security.Credentials;
-import android.security.KeyStore;
-
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.KeyFactorySpi;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.spec.ECPublicKeySpec;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.security.spec.PKCS8EncodedKeySpec;
-import java.security.spec.RSAPublicKeySpec;
-import java.security.spec.X509EncodedKeySpec;
-
-/**
- * {@link KeyFactorySpi} backed by Android KeyStore.
- *
- * @hide
- */
-public class AndroidKeyStoreKeyFactorySpi extends KeyFactorySpi {
-
- private final KeyStore mKeyStore = KeyStore.getInstance();
-
- @Override
- protected <T extends KeySpec> T engineGetKeySpec(Key key, Class<T> keySpecClass)
- throws InvalidKeySpecException {
- if (key == null) {
- throw new InvalidKeySpecException("key == null");
- } else if ((!(key instanceof AndroidKeyStorePrivateKey))
- && (!(key instanceof AndroidKeyStorePublicKey))) {
- throw new InvalidKeySpecException(
- "Unsupported key type: " + key.getClass().getName()
- + ". This KeyFactory supports only Android Keystore asymmetric keys");
- }
-
- // key is an Android Keystore private or public key
-
- if (keySpecClass == null) {
- throw new InvalidKeySpecException("keySpecClass == null");
- } else if (KeyInfo.class.equals(keySpecClass)) {
- if (!(key instanceof AndroidKeyStorePrivateKey)) {
- throw new InvalidKeySpecException(
- "Unsupported key type: " + key.getClass().getName()
- + ". KeyInfo can be obtained only for Android Keystore private keys");
- }
- AndroidKeyStorePrivateKey keystorePrivateKey = (AndroidKeyStorePrivateKey) key;
- String keyAliasInKeystore = keystorePrivateKey.getAlias();
- String entryAlias;
- if (keyAliasInKeystore.startsWith(Credentials.USER_PRIVATE_KEY)) {
- entryAlias = keyAliasInKeystore.substring(Credentials.USER_PRIVATE_KEY.length());
- } else {
- throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
- }
- @SuppressWarnings("unchecked")
- T result = (T) AndroidKeyStoreSecretKeyFactorySpi.getKeyInfo(
- mKeyStore, entryAlias, keyAliasInKeystore, keystorePrivateKey.getUid());
- return result;
- } else if (X509EncodedKeySpec.class.equals(keySpecClass)) {
- if (!(key instanceof AndroidKeyStorePublicKey)) {
- throw new InvalidKeySpecException(
- "Unsupported key type: " + key.getClass().getName()
- + ". X509EncodedKeySpec can be obtained only for Android Keystore public"
- + " keys");
- }
- @SuppressWarnings("unchecked")
- T result = (T) new X509EncodedKeySpec(((AndroidKeyStorePublicKey) key).getEncoded());
- return result;
- } else if (PKCS8EncodedKeySpec.class.equals(keySpecClass)) {
- if (key instanceof AndroidKeyStorePrivateKey) {
- throw new InvalidKeySpecException(
- "Key material export of Android Keystore private keys is not supported");
- } else {
- throw new InvalidKeySpecException(
- "Cannot export key material of public key in PKCS#8 format."
- + " Only X.509 format (X509EncodedKeySpec) supported for public keys.");
- }
- } else if (RSAPublicKeySpec.class.equals(keySpecClass)) {
- if (key instanceof AndroidKeyStoreRSAPublicKey) {
- AndroidKeyStoreRSAPublicKey rsaKey = (AndroidKeyStoreRSAPublicKey) key;
- @SuppressWarnings("unchecked")
- T result =
- (T) new RSAPublicKeySpec(rsaKey.getModulus(), rsaKey.getPublicExponent());
- return result;
- } else {
- throw new InvalidKeySpecException(
- "Obtaining RSAPublicKeySpec not supported for " + key.getAlgorithm() + " "
- + ((key instanceof AndroidKeyStorePrivateKey) ? "private" : "public")
- + " key");
- }
- } else if (ECPublicKeySpec.class.equals(keySpecClass)) {
- if (key instanceof AndroidKeyStoreECPublicKey) {
- AndroidKeyStoreECPublicKey ecKey = (AndroidKeyStoreECPublicKey) key;
- @SuppressWarnings("unchecked")
- T result = (T) new ECPublicKeySpec(ecKey.getW(), ecKey.getParams());
- return result;
- } else {
- throw new InvalidKeySpecException(
- "Obtaining ECPublicKeySpec not supported for " + key.getAlgorithm() + " "
- + ((key instanceof AndroidKeyStorePrivateKey) ? "private" : "public")
- + " key");
- }
- } else {
- throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
- }
- }
-
- @Override
- protected PrivateKey engineGeneratePrivate(KeySpec spec) throws InvalidKeySpecException {
- throw new InvalidKeySpecException(
- "To generate a key pair in Android Keystore, use KeyPairGenerator initialized with"
- + " " + KeyGenParameterSpec.class.getName());
- }
-
- @Override
- protected PublicKey engineGeneratePublic(KeySpec spec) throws InvalidKeySpecException {
- throw new InvalidKeySpecException(
- "To generate a key pair in Android Keystore, use KeyPairGenerator initialized with"
- + " " + KeyGenParameterSpec.class.getName());
- }
-
- @Override
- protected Key engineTranslateKey(Key key) throws InvalidKeyException {
- if (key == null) {
- throw new InvalidKeyException("key == null");
- } else if ((!(key instanceof AndroidKeyStorePrivateKey))
- && (!(key instanceof AndroidKeyStorePublicKey))) {
- throw new InvalidKeyException(
- "To import a key into Android Keystore, use KeyStore.setEntry");
- }
- return key;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
deleted file mode 100644
index fedde42..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ /dev/null
@@ -1,352 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.security.Credentials;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keystore.KeyGenParameterSpec;
-import android.security.keystore.KeyProperties;
-
-import libcore.util.EmptyArray;
-
-import java.security.InvalidAlgorithmParameterException;
-import java.security.ProviderException;
-import java.security.SecureRandom;
-import java.security.spec.AlgorithmParameterSpec;
-import java.util.Arrays;
-
-import javax.crypto.KeyGeneratorSpi;
-import javax.crypto.SecretKey;
-
-/**
- * {@link KeyGeneratorSpi} backed by Android KeyStore.
- *
- * @hide
- */
-public abstract class AndroidKeyStoreKeyGeneratorSpi extends KeyGeneratorSpi {
-
- public static class AES extends AndroidKeyStoreKeyGeneratorSpi {
- public AES() {
- super(KeymasterDefs.KM_ALGORITHM_AES, 128);
- }
-
- @Override
- protected void engineInit(AlgorithmParameterSpec params, SecureRandom random)
- throws InvalidAlgorithmParameterException {
- super.engineInit(params, random);
- if ((mKeySizeBits != 128) && (mKeySizeBits != 192) && (mKeySizeBits != 256)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported key size: " + mKeySizeBits
- + ". Supported: 128, 192, 256.");
- }
- }
- }
-
- public static class DESede extends AndroidKeyStoreKeyGeneratorSpi {
- public DESede() {
- super(KeymasterDefs.KM_ALGORITHM_3DES, 168);
- }
- }
-
- protected static abstract class HmacBase extends AndroidKeyStoreKeyGeneratorSpi {
- protected HmacBase(int keymasterDigest) {
- super(KeymasterDefs.KM_ALGORITHM_HMAC,
- keymasterDigest,
- KeymasterUtils.getDigestOutputSizeBits(keymasterDigest));
- }
- }
-
- public static class HmacSHA1 extends HmacBase {
- public HmacSHA1() {
- super(KeymasterDefs.KM_DIGEST_SHA1);
- }
- }
-
- public static class HmacSHA224 extends HmacBase {
- public HmacSHA224() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_224);
- }
- }
-
- public static class HmacSHA256 extends HmacBase {
- public HmacSHA256() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_256);
- }
- }
-
- public static class HmacSHA384 extends HmacBase {
- public HmacSHA384() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_384);
- }
- }
-
- public static class HmacSHA512 extends HmacBase {
- public HmacSHA512() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- private final KeyStore mKeyStore = KeyStore.getInstance();
- private final int mKeymasterAlgorithm;
- private final int mKeymasterDigest;
- private final int mDefaultKeySizeBits;
-
- private KeyGenParameterSpec mSpec;
- private SecureRandom mRng;
-
- protected int mKeySizeBits;
- private int[] mKeymasterPurposes;
- private int[] mKeymasterBlockModes;
- private int[] mKeymasterPaddings;
- private int[] mKeymasterDigests;
-
- protected AndroidKeyStoreKeyGeneratorSpi(
- int keymasterAlgorithm,
- int defaultKeySizeBits) {
- this(keymasterAlgorithm, -1, defaultKeySizeBits);
- }
-
- protected AndroidKeyStoreKeyGeneratorSpi(
- int keymasterAlgorithm,
- int keymasterDigest,
- int defaultKeySizeBits) {
- mKeymasterAlgorithm = keymasterAlgorithm;
- mKeymasterDigest = keymasterDigest;
- mDefaultKeySizeBits = defaultKeySizeBits;
- if (mDefaultKeySizeBits <= 0) {
- throw new IllegalArgumentException("Default key size must be positive");
- }
-
- if ((mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) && (mKeymasterDigest == -1)) {
- throw new IllegalArgumentException(
- "Digest algorithm must be specified for HMAC key");
- }
- }
-
- @Override
- protected void engineInit(SecureRandom random) {
- throw new UnsupportedOperationException("Cannot initialize without a "
- + KeyGenParameterSpec.class.getName() + " parameter");
- }
-
- @Override
- protected void engineInit(int keySize, SecureRandom random) {
- throw new UnsupportedOperationException("Cannot initialize without a "
- + KeyGenParameterSpec.class.getName() + " parameter");
- }
-
- @Override
- protected void engineInit(AlgorithmParameterSpec params, SecureRandom random)
- throws InvalidAlgorithmParameterException {
- resetAll();
-
- boolean success = false;
- try {
- if ((params == null) || (!(params instanceof KeyGenParameterSpec))) {
- throw new InvalidAlgorithmParameterException("Cannot initialize without a "
- + KeyGenParameterSpec.class.getName() + " parameter");
- }
- KeyGenParameterSpec spec = (KeyGenParameterSpec) params;
- if (spec.getKeystoreAlias() == null) {
- throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
- }
-
- mRng = random;
- mSpec = spec;
-
- mKeySizeBits = (spec.getKeySize() != -1) ? spec.getKeySize() : mDefaultKeySizeBits;
- if (mKeySizeBits <= 0) {
- throw new InvalidAlgorithmParameterException(
- "Key size must be positive: " + mKeySizeBits);
- } else if ((mKeySizeBits % 8) != 0) {
- throw new InvalidAlgorithmParameterException(
- "Key size must be a multiple of 8: " + mKeySizeBits);
- }
-
- try {
- mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
- mKeymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
- spec.getEncryptionPaddings());
- if (spec.getSignaturePaddings().length > 0) {
- throw new InvalidAlgorithmParameterException(
- "Signature paddings not supported for symmetric key algorithms");
- }
- mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
- if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (spec.isRandomizedEncryptionRequired())) {
- for (int keymasterBlockMode : mKeymasterBlockModes) {
- if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
- keymasterBlockMode)) {
- throw new InvalidAlgorithmParameterException(
- "Randomized encryption (IND-CPA) required but may be violated"
- + " by block mode: "
- + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
- + ". See " + KeyGenParameterSpec.class.getName()
- + " documentation.");
- }
- }
- }
- if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_3DES) {
- if (mKeySizeBits != 168) {
- throw new InvalidAlgorithmParameterException(
- "3DES key size must be 168 bits.");
- }
- }
- if (mKeymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
- if (mKeySizeBits < 64 || mKeySizeBits > 512) {
- throw new InvalidAlgorithmParameterException(
- "HMAC key sizes must be within 64-512 bits, inclusive.");
- }
-
- // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
- // implies SHA-256 digest). Because keymaster HMAC key is authorized only for
- // one digest, we don't let algorithm parameter spec override the digest implied
- // by the key. If the spec specifies digests at all, it must specify only one
- // digest, the only implied by key algorithm.
- mKeymasterDigests = new int[] {mKeymasterDigest};
- if (spec.isDigestsSpecified()) {
- // Digest(s) explicitly specified in the spec. Check that the list
- // consists of exactly one digest, the one implied by key algorithm.
- int[] keymasterDigestsFromSpec =
- KeyProperties.Digest.allToKeymaster(spec.getDigests());
- if ((keymasterDigestsFromSpec.length != 1)
- || (keymasterDigestsFromSpec[0] != mKeymasterDigest)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported digests specification: "
- + Arrays.asList(spec.getDigests()) + ". Only "
- + KeyProperties.Digest.fromKeymaster(mKeymasterDigest)
- + " supported for this HMAC key algorithm");
- }
- }
- } else {
- // Key algorithm does not imply a digest.
- if (spec.isDigestsSpecified()) {
- mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
- } else {
- mKeymasterDigests = EmptyArray.INT;
- }
- }
-
- // Check that user authentication related parameters are acceptable. This method
- // will throw an IllegalStateException if there are issues (e.g., secure lock screen
- // not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec);
- } catch (IllegalStateException | IllegalArgumentException e) {
- throw new InvalidAlgorithmParameterException(e);
- }
-
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- private void resetAll() {
- mSpec = null;
- mRng = null;
- mKeySizeBits = -1;
- mKeymasterPurposes = null;
- mKeymasterPaddings = null;
- mKeymasterBlockModes = null;
- }
-
- @Override
- protected SecretKey engineGenerateKey() {
- KeyGenParameterSpec spec = mSpec;
- if (spec == null) {
- throw new IllegalStateException("Not initialized");
- }
-
- KeymasterArguments args = new KeymasterArguments();
- args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
- args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterPaddings);
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
- KeymasterUtils.addUserAuthArgs(args, spec);
- KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
- args,
- mKeymasterAlgorithm,
- mKeymasterBlockModes,
- mKeymasterDigests);
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- spec.getKeyValidityForOriginationEnd());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- spec.getKeyValidityForConsumptionEnd());
-
- if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (!spec.isRandomizedEncryptionRequired())) {
- // Permit caller-provided IV when encrypting with this key
- args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
- }
-
- byte[] additionalEntropy =
- KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- mRng, (mKeySizeBits + 7) / 8);
- int flags = 0;
- if (spec.isStrongBoxBacked()) {
- flags |= KeyStore.FLAG_STRONGBOX;
- }
- if (spec.isCriticalToDeviceEncryption()) {
- flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
- }
- String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + spec.getKeystoreAlias();
- KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
- boolean success = false;
- try {
- Credentials.deleteAllTypesForAlias(mKeyStore, spec.getKeystoreAlias(), spec.getUid());
- int errorCode = mKeyStore.generateKey(
- keyAliasInKeystore,
- args,
- additionalEntropy,
- spec.getUid(),
- flags,
- resultingKeyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
- throw new StrongBoxUnavailableException("Failed to generate key");
- } else {
- throw new ProviderException(
- "Keystore operation failed", KeyStore.getKeyStoreException(errorCode));
- }
- }
- @KeyProperties.KeyAlgorithmEnum String keyAlgorithmJCA;
- try {
- keyAlgorithmJCA = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
- mKeymasterAlgorithm, mKeymasterDigest);
- } catch (IllegalArgumentException e) {
- throw new ProviderException("Failed to obtain JCA secret key algorithm name", e);
- }
- SecretKey result = new AndroidKeyStoreSecretKey(
- keyAliasInKeystore, spec.getUid(), keyAlgorithmJCA);
- success = true;
- return result;
- } finally {
- if (!success) {
- Credentials.deleteAllTypesForAlias(
- mKeyStore, spec.getKeystoreAlias(), spec.getUid());
- }
- }
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
deleted file mode 100644
index 988838b..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ /dev/null
@@ -1,986 +0,0 @@
-/*
- * Copyright (C) 2012 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.keystore;
-
-import android.annotation.Nullable;
-import android.content.Context;
-import android.os.Build;
-import android.security.Credentials;
-import android.security.KeyPairGeneratorSpec;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterCertificateChain;
-import android.security.keymaster.KeymasterDefs;
-import android.telephony.TelephonyManager;
-import android.util.ArraySet;
-
-import com.android.internal.org.bouncycastle.asn1.ASN1EncodableVector;
-import com.android.internal.org.bouncycastle.asn1.ASN1InputStream;
-import com.android.internal.org.bouncycastle.asn1.ASN1Integer;
-import com.android.internal.org.bouncycastle.asn1.ASN1ObjectIdentifier;
-import com.android.internal.org.bouncycastle.asn1.DERBitString;
-import com.android.internal.org.bouncycastle.asn1.DERNull;
-import com.android.internal.org.bouncycastle.asn1.DERSequence;
-import com.android.internal.org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
-import com.android.internal.org.bouncycastle.asn1.x509.AlgorithmIdentifier;
-import com.android.internal.org.bouncycastle.asn1.x509.Certificate;
-import com.android.internal.org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
-import com.android.internal.org.bouncycastle.asn1.x509.TBSCertificate;
-import com.android.internal.org.bouncycastle.asn1.x509.Time;
-import com.android.internal.org.bouncycastle.asn1.x509.V3TBSCertificateGenerator;
-import com.android.internal.org.bouncycastle.asn1.x9.X9ObjectIdentifiers;
-import com.android.internal.org.bouncycastle.jce.X509Principal;
-import com.android.internal.org.bouncycastle.jce.provider.X509CertificateObject;
-import com.android.internal.org.bouncycastle.x509.X509V3CertificateGenerator;
-
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.math.BigInteger;
-import java.nio.charset.StandardCharsets;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.KeyPair;
-import java.security.KeyPairGenerator;
-import java.security.KeyPairGeneratorSpi;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateParsingException;
-import java.security.cert.X509Certificate;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.ECGenParameterSpec;
-import java.security.spec.RSAKeyGenParameterSpec;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Locale;
-import java.util.Map;
-import java.util.Set;
-
-/**
- * Provides a way to create instances of a KeyPair which will be placed in the
- * Android keystore service usable only by the application that called it. This
- * can be used in conjunction with
- * {@link java.security.KeyStore#getInstance(String)} using the
- * {@code "AndroidKeyStore"} type.
- * <p>
- * This class can not be directly instantiated and must instead be used via the
- * {@link KeyPairGenerator#getInstance(String)
- * KeyPairGenerator.getInstance("AndroidKeyStore")} API.
- *
- * @hide
- */
-public abstract class AndroidKeyStoreKeyPairGeneratorSpi extends KeyPairGeneratorSpi {
-
- public static class RSA extends AndroidKeyStoreKeyPairGeneratorSpi {
- public RSA() {
- super(KeymasterDefs.KM_ALGORITHM_RSA);
- }
- }
-
- public static class EC extends AndroidKeyStoreKeyPairGeneratorSpi {
- public EC() {
- super(KeymasterDefs.KM_ALGORITHM_EC);
- }
- }
-
- /*
- * These must be kept in sync with system/security/keystore/defaults.h
- */
-
- /* EC */
- private static final int EC_DEFAULT_KEY_SIZE = 256;
-
- /* RSA */
- private static final int RSA_DEFAULT_KEY_SIZE = 2048;
- private static final int RSA_MIN_KEY_SIZE = 512;
- private static final int RSA_MAX_KEY_SIZE = 8192;
-
- private static final Map<String, Integer> SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE =
- new HashMap<String, Integer>();
- private static final List<String> SUPPORTED_EC_NIST_CURVE_NAMES = new ArrayList<String>();
- private static final List<Integer> SUPPORTED_EC_NIST_CURVE_SIZES = new ArrayList<Integer>();
- static {
- // Aliases for NIST P-224
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-224", 224);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp224r1", 224);
-
-
- // Aliases for NIST P-256
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-256", 256);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp256r1", 256);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("prime256v1", 256);
-
- // Aliases for NIST P-384
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-384", 384);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp384r1", 384);
-
- // Aliases for NIST P-521
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("p-521", 521);
- SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.put("secp521r1", 521);
-
- SUPPORTED_EC_NIST_CURVE_NAMES.addAll(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.keySet());
- Collections.sort(SUPPORTED_EC_NIST_CURVE_NAMES);
-
- SUPPORTED_EC_NIST_CURVE_SIZES.addAll(
- new HashSet<Integer>(SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.values()));
- Collections.sort(SUPPORTED_EC_NIST_CURVE_SIZES);
- }
-
- private final int mOriginalKeymasterAlgorithm;
-
- private KeyStore mKeyStore;
-
- private KeyGenParameterSpec mSpec;
-
- private String mEntryAlias;
- private int mEntryUid;
- private boolean mEncryptionAtRestRequired;
- private @KeyProperties.KeyAlgorithmEnum String mJcaKeyAlgorithm;
- private int mKeymasterAlgorithm = -1;
- private int mKeySizeBits;
- private SecureRandom mRng;
-
- private int[] mKeymasterPurposes;
- private int[] mKeymasterBlockModes;
- private int[] mKeymasterEncryptionPaddings;
- private int[] mKeymasterSignaturePaddings;
- private int[] mKeymasterDigests;
-
- private BigInteger mRSAPublicExponent;
-
- protected AndroidKeyStoreKeyPairGeneratorSpi(int keymasterAlgorithm) {
- mOriginalKeymasterAlgorithm = keymasterAlgorithm;
- }
-
- @SuppressWarnings("deprecation")
- @Override
- public void initialize(int keysize, SecureRandom random) {
- throw new IllegalArgumentException(
- KeyGenParameterSpec.class.getName() + " or " + KeyPairGeneratorSpec.class.getName()
- + " required to initialize this KeyPairGenerator");
- }
-
- @SuppressWarnings("deprecation")
- @Override
- public void initialize(AlgorithmParameterSpec params, SecureRandom random)
- throws InvalidAlgorithmParameterException {
- resetAll();
-
- boolean success = false;
- try {
- if (params == null) {
- throw new InvalidAlgorithmParameterException(
- "Must supply params of type " + KeyGenParameterSpec.class.getName()
- + " or " + KeyPairGeneratorSpec.class.getName());
- }
-
- KeyGenParameterSpec spec;
- boolean encryptionAtRestRequired = false;
- int keymasterAlgorithm = mOriginalKeymasterAlgorithm;
- if (params instanceof KeyGenParameterSpec) {
- spec = (KeyGenParameterSpec) params;
- } else if (params instanceof KeyPairGeneratorSpec) {
- // Legacy/deprecated spec
- KeyPairGeneratorSpec legacySpec = (KeyPairGeneratorSpec) params;
- try {
- KeyGenParameterSpec.Builder specBuilder;
- String specKeyAlgorithm = legacySpec.getKeyType();
- if (specKeyAlgorithm != null) {
- // Spec overrides the generator's default key algorithm
- try {
- keymasterAlgorithm =
- KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
- specKeyAlgorithm);
- } catch (IllegalArgumentException e) {
- throw new InvalidAlgorithmParameterException(
- "Invalid key type in parameters", e);
- }
- }
- switch (keymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_EC:
- specBuilder = new KeyGenParameterSpec.Builder(
- legacySpec.getKeystoreAlias(),
- KeyProperties.PURPOSE_SIGN
- | KeyProperties.PURPOSE_VERIFY);
- // Authorized to be used with any digest (including no digest).
- // MD5 was never offered for Android Keystore for ECDSA.
- specBuilder.setDigests(
- KeyProperties.DIGEST_NONE,
- KeyProperties.DIGEST_SHA1,
- KeyProperties.DIGEST_SHA224,
- KeyProperties.DIGEST_SHA256,
- KeyProperties.DIGEST_SHA384,
- KeyProperties.DIGEST_SHA512);
- break;
- case KeymasterDefs.KM_ALGORITHM_RSA:
- specBuilder = new KeyGenParameterSpec.Builder(
- legacySpec.getKeystoreAlias(),
- KeyProperties.PURPOSE_ENCRYPT
- | KeyProperties.PURPOSE_DECRYPT
- | KeyProperties.PURPOSE_SIGN
- | KeyProperties.PURPOSE_VERIFY);
- // Authorized to be used with any digest (including no digest).
- specBuilder.setDigests(
- KeyProperties.DIGEST_NONE,
- KeyProperties.DIGEST_MD5,
- KeyProperties.DIGEST_SHA1,
- KeyProperties.DIGEST_SHA224,
- KeyProperties.DIGEST_SHA256,
- KeyProperties.DIGEST_SHA384,
- KeyProperties.DIGEST_SHA512);
- // Authorized to be used with any encryption and signature padding
- // schemes (including no padding).
- specBuilder.setEncryptionPaddings(
- KeyProperties.ENCRYPTION_PADDING_NONE,
- KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
- KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
- specBuilder.setSignaturePaddings(
- KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
- KeyProperties.SIGNATURE_PADDING_RSA_PSS);
- // Disable randomized encryption requirement to support encryption
- // padding NONE above.
- specBuilder.setRandomizedEncryptionRequired(false);
- break;
- default:
- throw new ProviderException(
- "Unsupported algorithm: " + mKeymasterAlgorithm);
- }
-
- if (legacySpec.getKeySize() != -1) {
- specBuilder.setKeySize(legacySpec.getKeySize());
- }
- if (legacySpec.getAlgorithmParameterSpec() != null) {
- specBuilder.setAlgorithmParameterSpec(
- legacySpec.getAlgorithmParameterSpec());
- }
- specBuilder.setCertificateSubject(legacySpec.getSubjectDN());
- specBuilder.setCertificateSerialNumber(legacySpec.getSerialNumber());
- specBuilder.setCertificateNotBefore(legacySpec.getStartDate());
- specBuilder.setCertificateNotAfter(legacySpec.getEndDate());
- encryptionAtRestRequired = legacySpec.isEncryptionRequired();
- specBuilder.setUserAuthenticationRequired(false);
-
- spec = specBuilder.build();
- } catch (NullPointerException | IllegalArgumentException e) {
- throw new InvalidAlgorithmParameterException(e);
- }
- } else {
- throw new InvalidAlgorithmParameterException(
- "Unsupported params class: " + params.getClass().getName()
- + ". Supported: " + KeyGenParameterSpec.class.getName()
- + ", " + KeyPairGeneratorSpec.class.getName());
- }
-
- mEntryAlias = spec.getKeystoreAlias();
- mEntryUid = spec.getUid();
- mSpec = spec;
- mKeymasterAlgorithm = keymasterAlgorithm;
- mEncryptionAtRestRequired = encryptionAtRestRequired;
- mKeySizeBits = spec.getKeySize();
- initAlgorithmSpecificParameters();
- if (mKeySizeBits == -1) {
- mKeySizeBits = getDefaultKeySize(keymasterAlgorithm);
- }
- checkValidKeySize(keymasterAlgorithm, mKeySizeBits, mSpec.isStrongBoxBacked());
-
- if (spec.getKeystoreAlias() == null) {
- throw new InvalidAlgorithmParameterException("KeyStore entry alias not provided");
- }
-
- String jcaKeyAlgorithm;
- try {
- jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
- keymasterAlgorithm);
- mKeymasterPurposes = KeyProperties.Purpose.allToKeymaster(spec.getPurposes());
- mKeymasterBlockModes = KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes());
- mKeymasterEncryptionPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
- spec.getEncryptionPaddings());
- if (((spec.getPurposes() & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (spec.isRandomizedEncryptionRequired())) {
- for (int keymasterPadding : mKeymasterEncryptionPaddings) {
- if (!KeymasterUtils
- .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
- keymasterPadding)) {
- throw new InvalidAlgorithmParameterException(
- "Randomized encryption (IND-CPA) required but may be violated"
- + " by padding scheme: "
- + KeyProperties.EncryptionPadding.fromKeymaster(
- keymasterPadding)
- + ". See " + KeyGenParameterSpec.class.getName()
- + " documentation.");
- }
- }
- }
- mKeymasterSignaturePaddings = KeyProperties.SignaturePadding.allToKeymaster(
- spec.getSignaturePaddings());
- if (spec.isDigestsSpecified()) {
- mKeymasterDigests = KeyProperties.Digest.allToKeymaster(spec.getDigests());
- } else {
- mKeymasterDigests = EmptyArray.INT;
- }
-
- // Check that user authentication related parameters are acceptable. This method
- // will throw an IllegalStateException if there are issues (e.g., secure lock screen
- // not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
- } catch (IllegalArgumentException | IllegalStateException e) {
- throw new InvalidAlgorithmParameterException(e);
- }
-
- mJcaKeyAlgorithm = jcaKeyAlgorithm;
- mRng = random;
- mKeyStore = KeyStore.getInstance();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- private void resetAll() {
- mEntryAlias = null;
- mEntryUid = KeyStore.UID_SELF;
- mJcaKeyAlgorithm = null;
- mKeymasterAlgorithm = -1;
- mKeymasterPurposes = null;
- mKeymasterBlockModes = null;
- mKeymasterEncryptionPaddings = null;
- mKeymasterSignaturePaddings = null;
- mKeymasterDigests = null;
- mKeySizeBits = 0;
- mSpec = null;
- mRSAPublicExponent = null;
- mEncryptionAtRestRequired = false;
- mRng = null;
- mKeyStore = null;
- }
-
- private void initAlgorithmSpecificParameters() throws InvalidAlgorithmParameterException {
- AlgorithmParameterSpec algSpecificSpec = mSpec.getAlgorithmParameterSpec();
- switch (mKeymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_RSA:
- {
- BigInteger publicExponent = null;
- if (algSpecificSpec instanceof RSAKeyGenParameterSpec) {
- RSAKeyGenParameterSpec rsaSpec = (RSAKeyGenParameterSpec) algSpecificSpec;
- if (mKeySizeBits == -1) {
- mKeySizeBits = rsaSpec.getKeysize();
- } else if (mKeySizeBits != rsaSpec.getKeysize()) {
- throw new InvalidAlgorithmParameterException("RSA key size must match "
- + " between " + mSpec + " and " + algSpecificSpec
- + ": " + mKeySizeBits + " vs " + rsaSpec.getKeysize());
- }
- publicExponent = rsaSpec.getPublicExponent();
- } else if (algSpecificSpec != null) {
- throw new InvalidAlgorithmParameterException(
- "RSA may only use RSAKeyGenParameterSpec");
- }
- if (publicExponent == null) {
- publicExponent = RSAKeyGenParameterSpec.F4;
- }
- if (publicExponent.compareTo(BigInteger.ZERO) < 1) {
- throw new InvalidAlgorithmParameterException(
- "RSA public exponent must be positive: " + publicExponent);
- }
- if (publicExponent.compareTo(KeymasterArguments.UINT64_MAX_VALUE) > 0) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported RSA public exponent: " + publicExponent
- + ". Maximum supported value: " + KeymasterArguments.UINT64_MAX_VALUE);
- }
- mRSAPublicExponent = publicExponent;
- break;
- }
- case KeymasterDefs.KM_ALGORITHM_EC:
- if (algSpecificSpec instanceof ECGenParameterSpec) {
- ECGenParameterSpec ecSpec = (ECGenParameterSpec) algSpecificSpec;
- String curveName = ecSpec.getName();
- Integer ecSpecKeySizeBits = SUPPORTED_EC_NIST_CURVE_NAME_TO_SIZE.get(
- curveName.toLowerCase(Locale.US));
- if (ecSpecKeySizeBits == null) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported EC curve name: " + curveName
- + ". Supported: " + SUPPORTED_EC_NIST_CURVE_NAMES);
- }
- if (mKeySizeBits == -1) {
- mKeySizeBits = ecSpecKeySizeBits;
- } else if (mKeySizeBits != ecSpecKeySizeBits) {
- throw new InvalidAlgorithmParameterException("EC key size must match "
- + " between " + mSpec + " and " + algSpecificSpec
- + ": " + mKeySizeBits + " vs " + ecSpecKeySizeBits);
- }
- } else if (algSpecificSpec != null) {
- throw new InvalidAlgorithmParameterException(
- "EC may only use ECGenParameterSpec");
- }
- break;
- default:
- throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
- }
- }
-
- @Override
- public KeyPair generateKeyPair() {
- if (mKeyStore == null || mSpec == null) {
- throw new IllegalStateException("Not initialized");
- }
-
- int flags = (mEncryptionAtRestRequired) ? KeyStore.FLAG_ENCRYPTED : 0;
- if (((flags & KeyStore.FLAG_ENCRYPTED) != 0)
- && (mKeyStore.state() != KeyStore.State.UNLOCKED)) {
- throw new IllegalStateException(
- "Encryption at rest using secure lock screen credential requested for key pair"
- + ", but the user has not yet entered the credential");
- }
-
- if (mSpec.isStrongBoxBacked()) {
- flags |= KeyStore.FLAG_STRONGBOX;
- }
- if (mSpec.isCriticalToDeviceEncryption()) {
- flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
- }
-
- byte[] additionalEntropy =
- KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- mRng, (mKeySizeBits + 7) / 8);
-
- Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
- final String privateKeyAlias = Credentials.USER_PRIVATE_KEY + mEntryAlias;
- boolean success = false;
- try {
- generateKeystoreKeyPair(
- privateKeyAlias, constructKeyGenerationArguments(), additionalEntropy, flags);
- KeyPair keyPair = loadKeystoreKeyPair(privateKeyAlias);
-
- storeCertificateChain(flags, createCertificateChain(privateKeyAlias, keyPair));
-
- success = true;
- return keyPair;
- } catch (ProviderException | IllegalArgumentException | DeviceIdAttestationException e) {
- if ((mSpec.getPurposes() & KeyProperties.PURPOSE_WRAP_KEY) != 0) {
- throw new SecureKeyImportUnavailableException(e);
- } else {
- throw new ProviderException(e);
- }
- } finally {
- if (!success) {
- Credentials.deleteAllTypesForAlias(mKeyStore, mEntryAlias, mEntryUid);
- }
- }
- }
-
- private Iterable<byte[]> createCertificateChain(final String privateKeyAlias, KeyPair keyPair)
- throws ProviderException, DeviceIdAttestationException {
- byte[] challenge = mSpec.getAttestationChallenge();
- if (challenge != null) {
- KeymasterArguments args = new KeymasterArguments();
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_CHALLENGE, challenge);
-
- if (mSpec.isDevicePropertiesAttestationIncluded()) {
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_BRAND,
- Build.BRAND.getBytes(StandardCharsets.UTF_8));
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_DEVICE,
- Build.DEVICE.getBytes(StandardCharsets.UTF_8));
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_PRODUCT,
- Build.PRODUCT.getBytes(StandardCharsets.UTF_8));
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MANUFACTURER,
- Build.MANUFACTURER.getBytes(StandardCharsets.UTF_8));
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MODEL,
- Build.MODEL.getBytes(StandardCharsets.UTF_8));
- }
-
- int[] idTypes = mSpec.getAttestationIds();
- if (idTypes != null) {
- final Set<Integer> idTypesSet = new ArraySet<>(idTypes.length);
- for (int idType : idTypes) {
- idTypesSet.add(idType);
- }
- TelephonyManager telephonyService = null;
- if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
- || idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
- telephonyService =
- (TelephonyManager) KeyStore.getApplicationContext().getSystemService(
- Context.TELEPHONY_SERVICE);
- if (telephonyService == null) {
- throw new DeviceIdAttestationException(
- "Unable to access telephony service");
- }
- }
- for (final Integer idType : idTypesSet) {
- switch (idType) {
- case AttestationUtils.ID_TYPE_SERIAL:
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_SERIAL,
- Build.getSerial().getBytes(StandardCharsets.UTF_8)
- );
- break;
- case AttestationUtils.ID_TYPE_IMEI: {
- final String imei = telephonyService.getImei(0);
- if (imei == null) {
- throw new DeviceIdAttestationException("Unable to retrieve IMEI");
- }
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_IMEI,
- imei.getBytes(StandardCharsets.UTF_8)
- );
- break;
- }
- case AttestationUtils.ID_TYPE_MEID: {
- final String meid = telephonyService.getMeid(0);
- if (meid == null) {
- throw new DeviceIdAttestationException("Unable to retrieve MEID");
- }
- args.addBytes(KeymasterDefs.KM_TAG_ATTESTATION_ID_MEID,
- meid.getBytes(StandardCharsets.UTF_8)
- );
- break;
- }
- case AttestationUtils.USE_INDIVIDUAL_ATTESTATION: {
- args.addBoolean(KeymasterDefs.KM_TAG_DEVICE_UNIQUE_ATTESTATION);
- break;
- }
- default:
- throw new IllegalArgumentException("Unknown device ID type " + idType);
- }
- }
- }
-
- return getAttestationChain(privateKeyAlias, keyPair, args);
- }
-
- // Very short certificate chain in the non-attestation case.
- return Collections.singleton(generateSelfSignedCertificateBytes(keyPair));
- }
-
- private void generateKeystoreKeyPair(final String privateKeyAlias, KeymasterArguments args,
- byte[] additionalEntropy, final int flags) throws ProviderException {
- KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
- int errorCode = mKeyStore.generateKey(privateKeyAlias, args, additionalEntropy,
- mEntryUid, flags, resultingKeyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- if (errorCode == KeyStore.HARDWARE_TYPE_UNAVAILABLE) {
- throw new StrongBoxUnavailableException("Failed to generate key pair");
- } else {
- throw new ProviderException(
- "Failed to generate key pair", KeyStore.getKeyStoreException(errorCode));
- }
- }
- }
-
- private KeyPair loadKeystoreKeyPair(final String privateKeyAlias) throws ProviderException {
- try {
- KeyPair result = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyPairFromKeystore(
- mKeyStore, privateKeyAlias, mEntryUid);
- if (!mJcaKeyAlgorithm.equalsIgnoreCase(result.getPrivate().getAlgorithm())) {
- throw new ProviderException(
- "Generated key pair algorithm does not match requested algorithm: "
- + result.getPrivate().getAlgorithm() + " vs " + mJcaKeyAlgorithm);
- }
- return result;
- } catch (UnrecoverableKeyException | KeyPermanentlyInvalidatedException e) {
- throw new ProviderException("Failed to load generated key pair from keystore", e);
- }
- }
-
- private KeymasterArguments constructKeyGenerationArguments()
- throws IllegalArgumentException, DeviceIdAttestationException {
- KeymasterArguments args = new KeymasterArguments();
- args.addUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, mKeySizeBits);
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, mKeymasterAlgorithm);
- args.addEnums(KeymasterDefs.KM_TAG_PURPOSE, mKeymasterPurposes);
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockModes);
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterEncryptionPaddings);
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, mKeymasterSignaturePaddings);
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigests);
-
- KeymasterUtils.addUserAuthArgs(args, mSpec);
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, mSpec.getKeyValidityStart());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- mSpec.getKeyValidityForOriginationEnd());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- mSpec.getKeyValidityForConsumptionEnd());
- addAlgorithmSpecificParameters(args);
-
- if (mSpec.isUniqueIdIncluded()) {
- args.addBoolean(KeymasterDefs.KM_TAG_INCLUDE_UNIQUE_ID);
- }
- return args;
- }
-
- private void storeCertificateChain(final int flags, Iterable<byte[]> iterable)
- throws ProviderException {
- Iterator<byte[]> iter = iterable.iterator();
- storeCertificate(
- Credentials.USER_CERTIFICATE, iter.next(), flags, "Failed to store certificate");
-
- if (!iter.hasNext()) {
- return;
- }
-
- ByteArrayOutputStream certificateConcatenationStream = new ByteArrayOutputStream();
- while (iter.hasNext()) {
- byte[] data = iter.next();
- certificateConcatenationStream.write(data, 0, data.length);
- }
-
- storeCertificate(Credentials.CA_CERTIFICATE, certificateConcatenationStream.toByteArray(),
- flags, "Failed to store attestation CA certificate");
- }
-
- private void storeCertificate(String prefix, byte[] certificateBytes, final int flags,
- String failureMessage) throws ProviderException {
- int insertErrorCode = mKeyStore.insert(
- prefix + mEntryAlias,
- certificateBytes,
- mEntryUid,
- flags);
- if (insertErrorCode != KeyStore.NO_ERROR) {
- throw new ProviderException(failureMessage,
- KeyStore.getKeyStoreException(insertErrorCode));
- }
- }
-
- private byte[] generateSelfSignedCertificateBytes(KeyPair keyPair) throws ProviderException {
- try {
- return generateSelfSignedCertificate(keyPair.getPrivate(), keyPair.getPublic())
- .getEncoded();
- } catch (IOException | CertificateParsingException e) {
- throw new ProviderException("Failed to generate self-signed certificate", e);
- } catch (CertificateEncodingException e) {
- throw new ProviderException(
- "Failed to obtain encoded form of self-signed certificate", e);
- }
- }
-
- private Iterable<byte[]> getAttestationChain(String privateKeyAlias,
- KeyPair keyPair, KeymasterArguments args)
- throws ProviderException {
- final KeymasterCertificateChain outChain = new KeymasterCertificateChain();
- final int errorCode;
- if (mSpec.isDevicePropertiesAttestationIncluded()
- && mSpec.getAttestationChallenge() == null) {
- throw new ProviderException("An attestation challenge must be provided when requesting "
- + "device properties attestation.");
- }
- errorCode = mKeyStore.attestKey(privateKeyAlias, args, outChain);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new ProviderException("Failed to generate attestation certificate chain",
- KeyStore.getKeyStoreException(errorCode));
- }
- Collection<byte[]> chain = outChain.getCertificates();
- if (chain.size() < 2) {
- throw new ProviderException("Attestation certificate chain contained "
- + chain.size() + " entries. At least two are required.");
- }
- return chain;
- }
-
- private void addAlgorithmSpecificParameters(KeymasterArguments keymasterArgs) {
- switch (mKeymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_RSA:
- keymasterArgs.addUnsignedLong(
- KeymasterDefs.KM_TAG_RSA_PUBLIC_EXPONENT, mRSAPublicExponent);
- break;
- case KeymasterDefs.KM_ALGORITHM_EC:
- break;
- default:
- throw new ProviderException("Unsupported algorithm: " + mKeymasterAlgorithm);
- }
- }
-
- private X509Certificate generateSelfSignedCertificate(PrivateKey privateKey,
- PublicKey publicKey) throws CertificateParsingException, IOException {
- String signatureAlgorithm =
- getCertificateSignatureAlgorithm(mKeymasterAlgorithm, mKeySizeBits, mSpec);
- if (signatureAlgorithm == null) {
- // Key cannot be used to sign a certificate
- return generateSelfSignedCertificateWithFakeSignature(publicKey);
- } else {
- // Key can be used to sign a certificate
- try {
- return generateSelfSignedCertificateWithValidSignature(
- privateKey, publicKey, signatureAlgorithm);
- } catch (Exception e) {
- // Failed to generate the self-signed certificate with valid signature. Fall back
- // to generating a self-signed certificate with a fake signature. This is done for
- // all exception types because we prefer key pair generation to succeed and end up
- // producing a self-signed certificate with an invalid signature to key pair
- // generation failing.
- return generateSelfSignedCertificateWithFakeSignature(publicKey);
- }
- }
- }
-
- @SuppressWarnings("deprecation")
- private X509Certificate generateSelfSignedCertificateWithValidSignature(
- PrivateKey privateKey, PublicKey publicKey, String signatureAlgorithm) throws Exception {
- final X509V3CertificateGenerator certGen = new X509V3CertificateGenerator();
- certGen.setPublicKey(publicKey);
- certGen.setSerialNumber(mSpec.getCertificateSerialNumber());
- certGen.setSubjectDN(mSpec.getCertificateSubject());
- certGen.setIssuerDN(mSpec.getCertificateSubject());
- certGen.setNotBefore(mSpec.getCertificateNotBefore());
- certGen.setNotAfter(mSpec.getCertificateNotAfter());
- certGen.setSignatureAlgorithm(signatureAlgorithm);
- return certGen.generate(privateKey);
- }
-
- @SuppressWarnings("deprecation")
- private X509Certificate generateSelfSignedCertificateWithFakeSignature(
- PublicKey publicKey) throws IOException, CertificateParsingException {
- V3TBSCertificateGenerator tbsGenerator = new V3TBSCertificateGenerator();
- ASN1ObjectIdentifier sigAlgOid;
- AlgorithmIdentifier sigAlgId;
- byte[] signature;
- switch (mKeymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_EC:
- sigAlgOid = X9ObjectIdentifiers.ecdsa_with_SHA256;
- sigAlgId = new AlgorithmIdentifier(sigAlgOid);
- ASN1EncodableVector v = new ASN1EncodableVector();
- v.add(new ASN1Integer(BigInteger.valueOf(0)));
- v.add(new ASN1Integer(BigInteger.valueOf(0)));
- signature = new DERSequence().getEncoded();
- break;
- case KeymasterDefs.KM_ALGORITHM_RSA:
- sigAlgOid = PKCSObjectIdentifiers.sha256WithRSAEncryption;
- sigAlgId = new AlgorithmIdentifier(sigAlgOid, DERNull.INSTANCE);
- signature = new byte[1];
- break;
- default:
- throw new ProviderException("Unsupported key algorithm: " + mKeymasterAlgorithm);
- }
-
- try (ASN1InputStream publicKeyInfoIn = new ASN1InputStream(publicKey.getEncoded())) {
- tbsGenerator.setSubjectPublicKeyInfo(
- SubjectPublicKeyInfo.getInstance(publicKeyInfoIn.readObject()));
- }
- tbsGenerator.setSerialNumber(new ASN1Integer(mSpec.getCertificateSerialNumber()));
- X509Principal subject =
- new X509Principal(mSpec.getCertificateSubject().getEncoded());
- tbsGenerator.setSubject(subject);
- tbsGenerator.setIssuer(subject);
- tbsGenerator.setStartDate(new Time(mSpec.getCertificateNotBefore()));
- tbsGenerator.setEndDate(new Time(mSpec.getCertificateNotAfter()));
- tbsGenerator.setSignature(sigAlgId);
- TBSCertificate tbsCertificate = tbsGenerator.generateTBSCertificate();
-
- ASN1EncodableVector result = new ASN1EncodableVector();
- result.add(tbsCertificate);
- result.add(sigAlgId);
- result.add(new DERBitString(signature));
- return new X509CertificateObject(Certificate.getInstance(new DERSequence(result)));
- }
-
- private static int getDefaultKeySize(int keymasterAlgorithm) {
- switch (keymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_EC:
- return EC_DEFAULT_KEY_SIZE;
- case KeymasterDefs.KM_ALGORITHM_RSA:
- return RSA_DEFAULT_KEY_SIZE;
- default:
- throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
- }
- }
-
- private static void checkValidKeySize(
- int keymasterAlgorithm,
- int keySize,
- boolean isStrongBoxBacked)
- throws InvalidAlgorithmParameterException {
- switch (keymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_EC:
- if (isStrongBoxBacked && keySize != 256) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported StrongBox EC key size: "
- + keySize + " bits. Supported: 256");
- }
- if (!SUPPORTED_EC_NIST_CURVE_SIZES.contains(keySize)) {
- throw new InvalidAlgorithmParameterException("Unsupported EC key size: "
- + keySize + " bits. Supported: " + SUPPORTED_EC_NIST_CURVE_SIZES);
- }
- break;
- case KeymasterDefs.KM_ALGORITHM_RSA:
- if (keySize < RSA_MIN_KEY_SIZE || keySize > RSA_MAX_KEY_SIZE) {
- throw new InvalidAlgorithmParameterException("RSA key size must be >= "
- + RSA_MIN_KEY_SIZE + " and <= " + RSA_MAX_KEY_SIZE);
- }
- break;
- default:
- throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
- }
- }
-
- /**
- * Returns the {@code Signature} algorithm to be used for signing a certificate using the
- * specified key or {@code null} if the key cannot be used for signing a certificate.
- */
- @Nullable
- private static String getCertificateSignatureAlgorithm(
- int keymasterAlgorithm,
- int keySizeBits,
- KeyGenParameterSpec spec) {
- // Constraints:
- // 1. Key must be authorized for signing without user authentication.
- // 2. Signature digest must be one of key's authorized digests.
- // 3. For RSA keys, the digest output size must not exceed modulus size minus space overhead
- // of RSA PKCS#1 signature padding scheme (about 30 bytes).
- // 4. For EC keys, the there is no point in using a digest whose output size is longer than
- // key/field size because the digest will be truncated to that size.
-
- if ((spec.getPurposes() & KeyProperties.PURPOSE_SIGN) == 0) {
- // Key not authorized for signing
- return null;
- }
- if (spec.isUserAuthenticationRequired()) {
- // Key not authorized for use without user authentication
- return null;
- }
- if (!spec.isDigestsSpecified()) {
- // Key not authorized for any digests -- can't sign
- return null;
- }
- switch (keymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_EC:
- {
- Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
- spec.getDigests(),
- AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
-
- int bestKeymasterDigest = -1;
- int bestDigestOutputSizeBits = -1;
- for (int keymasterDigest : availableKeymasterDigests) {
- int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
- if (outputSizeBits == keySizeBits) {
- // Perfect match -- use this digest
- bestKeymasterDigest = keymasterDigest;
- bestDigestOutputSizeBits = outputSizeBits;
- break;
- }
- // Not a perfect match -- check against the best digest so far
- if (bestKeymasterDigest == -1) {
- // First digest tested -- definitely the best so far
- bestKeymasterDigest = keymasterDigest;
- bestDigestOutputSizeBits = outputSizeBits;
- } else {
- // Prefer output size to be as close to key size as possible, with output
- // sizes larger than key size preferred to those smaller than key size.
- if (bestDigestOutputSizeBits < keySizeBits) {
- // Output size of the best digest so far is smaller than key size.
- // Anything larger is a win.
- if (outputSizeBits > bestDigestOutputSizeBits) {
- bestKeymasterDigest = keymasterDigest;
- bestDigestOutputSizeBits = outputSizeBits;
- }
- } else {
- // Output size of the best digest so far is larger than key size.
- // Anything smaller is a win, as long as it's not smaller than key size.
- if ((outputSizeBits < bestDigestOutputSizeBits)
- && (outputSizeBits >= keySizeBits)) {
- bestKeymasterDigest = keymasterDigest;
- bestDigestOutputSizeBits = outputSizeBits;
- }
- }
- }
- }
- if (bestKeymasterDigest == -1) {
- return null;
- }
- return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
- bestKeymasterDigest) + "WithECDSA";
- }
- case KeymasterDefs.KM_ALGORITHM_RSA:
- {
- // Check whether this key is authorized for PKCS#1 signature padding.
- // We use Bouncy Castle to generate self-signed RSA certificates. Bouncy Castle
- // only supports RSA certificates signed using PKCS#1 padding scheme. The key needs
- // to be authorized for PKCS#1 padding or padding NONE which means any padding.
- boolean pkcs1SignaturePaddingSupported =
- com.android.internal.util.ArrayUtils.contains(
- KeyProperties.SignaturePadding.allToKeymaster(
- spec.getSignaturePaddings()),
- KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
- if (!pkcs1SignaturePaddingSupported) {
- // Key not authorized for PKCS#1 signature padding -- can't sign
- return null;
- }
-
- Set<Integer> availableKeymasterDigests = getAvailableKeymasterSignatureDigests(
- spec.getDigests(),
- AndroidKeyStoreBCWorkaroundProvider.getSupportedEcdsaSignatureDigests());
-
- // The amount of space available for the digest is less than modulus size by about
- // 30 bytes because padding must be at least 11 bytes long (00 || 01 || PS || 00,
- // where PS must be at least 8 bytes long), and then there's also the 15--19 bytes
- // overhead (depending the on chosen digest) for encoding digest OID and digest
- // value in DER.
- int maxDigestOutputSizeBits = keySizeBits - 30 * 8;
- int bestKeymasterDigest = -1;
- int bestDigestOutputSizeBits = -1;
- for (int keymasterDigest : availableKeymasterDigests) {
- int outputSizeBits = KeymasterUtils.getDigestOutputSizeBits(keymasterDigest);
- if (outputSizeBits > maxDigestOutputSizeBits) {
- // Digest too long (signature generation will fail) -- skip
- continue;
- }
- if (bestKeymasterDigest == -1) {
- // First digest tested -- definitely the best so far
- bestKeymasterDigest = keymasterDigest;
- bestDigestOutputSizeBits = outputSizeBits;
- } else {
- // The longer the better
- if (outputSizeBits > bestDigestOutputSizeBits) {
- bestKeymasterDigest = keymasterDigest;
- bestDigestOutputSizeBits = outputSizeBits;
- }
- }
- }
- if (bestKeymasterDigest == -1) {
- return null;
- }
- return KeyProperties.Digest.fromKeymasterToSignatureAlgorithmDigest(
- bestKeymasterDigest) + "WithRSA";
- }
- default:
- throw new ProviderException("Unsupported algorithm: " + keymasterAlgorithm);
- }
- }
-
- private static Set<Integer> getAvailableKeymasterSignatureDigests(
- @KeyProperties.DigestEnum String[] authorizedKeyDigests,
- @KeyProperties.DigestEnum String[] supportedSignatureDigests) {
- Set<Integer> authorizedKeymasterKeyDigests = new HashSet<Integer>();
- for (int keymasterDigest : KeyProperties.Digest.allToKeymaster(authorizedKeyDigests)) {
- authorizedKeymasterKeyDigests.add(keymasterDigest);
- }
- Set<Integer> supportedKeymasterSignatureDigests = new HashSet<Integer>();
- for (int keymasterDigest
- : KeyProperties.Digest.allToKeymaster(supportedSignatureDigests)) {
- supportedKeymasterSignatureDigests.add(keymasterDigest);
- }
- Set<Integer> result = new HashSet<Integer>(supportedKeymasterSignatureDigests);
- result.retainAll(authorizedKeymasterKeyDigests);
- return result;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java b/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java
deleted file mode 100644
index 45d579e..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreLoadStoreParameter.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import java.security.KeyStore;
-import java.security.KeyStore.ProtectionParameter;
-
-class AndroidKeyStoreLoadStoreParameter implements KeyStore.LoadStoreParameter {
-
- private final int mUid;
-
- AndroidKeyStoreLoadStoreParameter(int uid) {
- mUid = uid;
- }
-
- @Override
- public ProtectionParameter getProtectionParameter() {
- return null;
- }
-
- int getUid() {
- return mUid;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java
deleted file mode 100644
index 06e4c88..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStorePrivateKey.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import java.security.PrivateKey;
-
-/**
- * {@link PrivateKey} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStorePrivateKey extends AndroidKeyStoreKey implements PrivateKey {
-
- public AndroidKeyStorePrivateKey(String alias, int uid, String algorithm) {
- super(alias, uid, algorithm);
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
index 0871517..ecb082e 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreProvider.java
@@ -20,30 +20,13 @@
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.security.KeyStore;
-import android.security.keymaster.ExportResult;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterDefs;
import java.io.IOException;
-import java.security.KeyFactory;
-import java.security.KeyPair;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.Provider;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.Signature;
-import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
-import java.security.interfaces.ECKey;
-import java.security.interfaces.ECPublicKey;
-import java.security.interfaces.RSAKey;
-import java.security.interfaces.RSAPublicKey;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.X509EncodedKeySpec;
-import java.util.List;
import javax.crypto.Cipher;
import javax.crypto.Mac;
@@ -57,117 +40,10 @@
public class AndroidKeyStoreProvider extends Provider {
private static final String PROVIDER_NAME = "AndroidKeyStore";
- // IMPLEMENTATION NOTE: Class names are hard-coded in this provider to avoid loading these
- // classes when this provider is instantiated and installed early on during each app's
- // initialization process.
- //
- // Crypto operations operating on the AndroidKeyStore keys must not be offered by this provider.
- // Instead, they need to be offered by AndroidKeyStoreBCWorkaroundProvider. See its Javadoc
- // for details.
-
- private static final String PACKAGE_NAME = "android.security.keystore";
-
- private static final String DESEDE_SYSTEM_PROPERTY =
- "ro.hardware.keystore_desede";
-
/** @hide */
- public AndroidKeyStoreProvider() {
- this(PROVIDER_NAME);
- }
-
- /** @hide **/
- public AndroidKeyStoreProvider(String providerName) {
- super(providerName, 1.0, "Android KeyStore security provider");
-
- boolean supports3DES = "true".equals(android.os.SystemProperties.get(DESEDE_SYSTEM_PROPERTY));
-
- // java.security.KeyStore
- put("KeyStore." + providerName, PACKAGE_NAME + ".AndroidKeyStoreSpi");
-
- // java.security.KeyPairGenerator
- put("KeyPairGenerator.EC", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$EC");
- put("KeyPairGenerator.RSA", PACKAGE_NAME + ".AndroidKeyStoreKeyPairGeneratorSpi$RSA");
-
- // java.security.KeyFactory
- putKeyFactoryImpl("EC");
- putKeyFactoryImpl("RSA");
-
- // javax.crypto.KeyGenerator
- put("KeyGenerator.AES", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$AES");
- put("KeyGenerator.HmacSHA1", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA1");
- put("KeyGenerator.HmacSHA224", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA224");
- put("KeyGenerator.HmacSHA256", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA256");
- put("KeyGenerator.HmacSHA384", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA384");
- put("KeyGenerator.HmacSHA512", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$HmacSHA512");
-
- if (supports3DES) {
- put("KeyGenerator.DESede", PACKAGE_NAME + ".AndroidKeyStoreKeyGeneratorSpi$DESede");
- }
-
- // java.security.SecretKeyFactory
- putSecretKeyFactoryImpl("AES");
- if (supports3DES) {
- putSecretKeyFactoryImpl("DESede");
- }
- putSecretKeyFactoryImpl("HmacSHA1");
- putSecretKeyFactoryImpl("HmacSHA224");
- putSecretKeyFactoryImpl("HmacSHA256");
- putSecretKeyFactoryImpl("HmacSHA384");
- putSecretKeyFactoryImpl("HmacSHA512");
- }
-
- /**
- * This function indicates whether or not Keystore 2.0 is enabled. Some parts of the
- * Keystore SPI must behave subtly differently when Keystore 2.0 is enabled. However,
- * the platform property that indicates that Keystore 2.0 is enabled is not readable
- * by applications. So we set this value when {@code install()} is called because it
- * is called by zygote, which can access Keystore2Properties.
- *
- * This function can be removed once the transition to Keystore 2.0 is complete.
- * b/171305684
- *
- * @return true if Keystore 2.0 is enabled.
- * @hide
- */
- public static boolean isKeystore2Enabled() {
- return android.security.keystore2.AndroidKeyStoreProvider.isInstalled();
- }
-
- /**
- * Installs a new instance of this provider (and the
- * {@link AndroidKeyStoreBCWorkaroundProvider}).
- * @hide
- */
- public static void install() {
- Provider[] providers = Security.getProviders();
- int bcProviderIndex = -1;
- for (int i = 0; i < providers.length; i++) {
- Provider provider = providers[i];
- if ("BC".equals(provider.getName())) {
- bcProviderIndex = i;
- break;
- }
- }
-
- Security.addProvider(new AndroidKeyStoreProvider());
- Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider();
- if (bcProviderIndex != -1) {
- // Bouncy Castle provider found -- install the workaround provider above it.
- // insertProviderAt uses 1-based positions.
- Security.insertProviderAt(workaroundProvider, bcProviderIndex + 1);
- } else {
- // Bouncy Castle provider not found -- install the workaround provider at lowest
- // priority.
- Security.addProvider(workaroundProvider);
- }
- }
-
- private void putSecretKeyFactoryImpl(String algorithm) {
- put("SecretKeyFactory." + algorithm, PACKAGE_NAME + ".AndroidKeyStoreSecretKeyFactorySpi");
- }
-
- private void putKeyFactoryImpl(String algorithm) {
- put("KeyFactory." + algorithm, PACKAGE_NAME + ".AndroidKeyStoreKeyFactorySpi");
+ public AndroidKeyStoreProvider(@NonNull String name) {
+ super(name, 1.0, "Android KeyStore security provider");
+ throw new IllegalStateException("Should not be instantiated.");
}
/**
@@ -189,229 +65,7 @@
if (cryptoPrimitive == null) {
throw new NullPointerException();
}
- Object spi;
- if (cryptoPrimitive instanceof Signature) {
- spi = ((Signature) cryptoPrimitive).getCurrentSpi();
- } else if (cryptoPrimitive instanceof Mac) {
- spi = ((Mac) cryptoPrimitive).getCurrentSpi();
- } else if (cryptoPrimitive instanceof Cipher) {
- spi = ((Cipher) cryptoPrimitive).getCurrentSpi();
- } else {
- throw new IllegalArgumentException("Unsupported crypto primitive: " + cryptoPrimitive
- + ". Supported: Signature, Mac, Cipher");
- }
- if (spi == null) {
- throw new IllegalStateException("Crypto primitive not initialized");
- } else if (!(spi instanceof KeyStoreCryptoOperation)) {
- throw new IllegalArgumentException(
- "Crypto primitive not backed by AndroidKeyStore provider: " + cryptoPrimitive
- + ", spi: " + spi);
- }
- return ((KeyStoreCryptoOperation) spi).getOperationHandle();
- }
-
- /** @hide **/
- @NonNull
- public static AndroidKeyStorePublicKey getAndroidKeyStorePublicKey(
- @NonNull String alias,
- int uid,
- @NonNull @KeyProperties.KeyAlgorithmEnum String keyAlgorithm,
- @NonNull byte[] x509EncodedForm) {
- PublicKey publicKey;
- try {
- KeyFactory keyFactory = KeyFactory.getInstance(keyAlgorithm);
- publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(x509EncodedForm));
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain " + keyAlgorithm + " KeyFactory", e);
- } catch (InvalidKeySpecException e) {
- throw new ProviderException("Invalid X.509 encoding of public key", e);
- }
- if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
- return new AndroidKeyStoreECPublicKey(alias, uid, (ECPublicKey) publicKey);
- } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
- return new AndroidKeyStoreRSAPublicKey(alias, uid, (RSAPublicKey) publicKey);
- } else {
- throw new ProviderException("Unsupported Android Keystore public key algorithm: "
- + keyAlgorithm);
- }
- }
-
- @NonNull
- private static AndroidKeyStorePrivateKey getAndroidKeyStorePrivateKey(
- @NonNull AndroidKeyStorePublicKey publicKey) {
- String keyAlgorithm = publicKey.getAlgorithm();
- if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
- return new AndroidKeyStoreECPrivateKey(
- publicKey.getAlias(), publicKey.getUid(), ((ECKey) publicKey).getParams());
- } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
- return new AndroidKeyStoreRSAPrivateKey(
- publicKey.getAlias(), publicKey.getUid(), ((RSAKey) publicKey).getModulus());
- } else {
- throw new ProviderException("Unsupported Android Keystore public key algorithm: "
- + keyAlgorithm);
- }
- }
-
- @NonNull
- private static KeyCharacteristics getKeyCharacteristics(@NonNull KeyStore keyStore,
- @NonNull String alias, int uid)
- throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- int errorCode = keyStore.getKeyCharacteristics(
- alias, null, null, uid, keyCharacteristics);
- if (errorCode == KeyStore.KEY_PERMANENTLY_INVALIDATED) {
- throw (KeyPermanentlyInvalidatedException)
- new KeyPermanentlyInvalidatedException(
- "User changed or deleted their auth credentials",
- KeyStore.getKeyStoreException(errorCode));
- }
- if (errorCode != KeyStore.NO_ERROR) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Failed to obtain information about key")
- .initCause(KeyStore.getKeyStoreException(errorCode));
- }
- return keyCharacteristics;
- }
-
- @NonNull
- private static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid,
- KeyCharacteristics keyCharacteristics)
- throws UnrecoverableKeyException {
- ExportResult exportResult = keyStore.exportKey(
- privateKeyAlias, KeymasterDefs.KM_KEY_FORMAT_X509, null, null, uid);
- if (exportResult.resultCode != KeyStore.NO_ERROR) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Failed to obtain X.509 form of public key")
- .initCause(KeyStore.getKeyStoreException(exportResult.resultCode));
- }
- final byte[] x509EncodedPublicKey = exportResult.exportData;
-
- Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
- if (keymasterAlgorithm == null) {
- throw new UnrecoverableKeyException("Key algorithm unknown");
- }
-
- String jcaKeyAlgorithm;
- try {
- jcaKeyAlgorithm = KeyProperties.KeyAlgorithm.fromKeymasterAsymmetricKeyAlgorithm(
- keymasterAlgorithm);
- } catch (IllegalArgumentException e) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Failed to load private key")
- .initCause(e);
- }
-
- return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
- privateKeyAlias, uid, jcaKeyAlgorithm, x509EncodedPublicKey);
- }
-
- /** @hide **/
- @NonNull
- public static AndroidKeyStorePublicKey loadAndroidKeyStorePublicKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
- throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- return loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias, uid,
- getKeyCharacteristics(keyStore, privateKeyAlias, uid));
- }
-
- @NonNull
- private static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid,
- @NonNull KeyCharacteristics keyCharacteristics)
- throws UnrecoverableKeyException {
- AndroidKeyStorePublicKey publicKey =
- loadAndroidKeyStorePublicKeyFromKeystore(keyStore, privateKeyAlias, uid,
- keyCharacteristics);
- AndroidKeyStorePrivateKey privateKey =
- AndroidKeyStoreProvider.getAndroidKeyStorePrivateKey(publicKey);
- return new KeyPair(publicKey, privateKey);
- }
-
- /** @hide **/
- @NonNull
- public static KeyPair loadAndroidKeyStoreKeyPairFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
- throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- return loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias, uid,
- getKeyCharacteristics(keyStore, privateKeyAlias, uid));
- }
-
- @NonNull
- private static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid,
- @NonNull KeyCharacteristics keyCharacteristics)
- throws UnrecoverableKeyException {
- KeyPair keyPair = loadAndroidKeyStoreKeyPairFromKeystore(keyStore, privateKeyAlias, uid,
- keyCharacteristics);
- return (AndroidKeyStorePrivateKey) keyPair.getPrivate();
- }
-
- /** @hide **/
- @NonNull
- public static AndroidKeyStorePrivateKey loadAndroidKeyStorePrivateKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String privateKeyAlias, int uid)
- throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- return loadAndroidKeyStorePrivateKeyFromKeystore(keyStore, privateKeyAlias, uid,
- getKeyCharacteristics(keyStore, privateKeyAlias, uid));
- }
-
- @NonNull
- private static AndroidKeyStoreSecretKey loadAndroidKeyStoreSecretKeyFromKeystore(
- @NonNull String secretKeyAlias, int uid, @NonNull KeyCharacteristics keyCharacteristics)
- throws UnrecoverableKeyException {
- Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
- if (keymasterAlgorithm == null) {
- throw new UnrecoverableKeyException("Key algorithm unknown");
- }
-
- List<Integer> keymasterDigests = keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_DIGEST);
- int keymasterDigest;
- if (keymasterDigests.isEmpty()) {
- keymasterDigest = -1;
- } else {
- // More than one digest can be permitted for this key. Use the first one to form the
- // JCA key algorithm name.
- keymasterDigest = keymasterDigests.get(0);
- }
-
- @KeyProperties.KeyAlgorithmEnum String keyAlgorithmString;
- try {
- keyAlgorithmString = KeyProperties.KeyAlgorithm.fromKeymasterSecretKeyAlgorithm(
- keymasterAlgorithm, keymasterDigest);
- } catch (IllegalArgumentException e) {
- throw (UnrecoverableKeyException)
- new UnrecoverableKeyException("Unsupported secret key type").initCause(e);
- }
-
- return new AndroidKeyStoreSecretKey(secretKeyAlias, uid, keyAlgorithmString);
- }
-
- /** @hide **/
- @NonNull
- public static AndroidKeyStoreKey loadAndroidKeyStoreKeyFromKeystore(
- @NonNull KeyStore keyStore, @NonNull String userKeyAlias, int uid)
- throws UnrecoverableKeyException, KeyPermanentlyInvalidatedException {
- KeyCharacteristics keyCharacteristics = getKeyCharacteristics(keyStore, userKeyAlias, uid);
-
- Integer keymasterAlgorithm = keyCharacteristics.getEnum(KeymasterDefs.KM_TAG_ALGORITHM);
- if (keymasterAlgorithm == null) {
- throw new UnrecoverableKeyException("Key algorithm unknown");
- }
-
- if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC ||
- keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_AES ||
- keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_3DES) {
- return loadAndroidKeyStoreSecretKeyFromKeystore(userKeyAlias, uid,
- keyCharacteristics);
- } else if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_RSA ||
- keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC) {
- return loadAndroidKeyStorePrivateKeyFromKeystore(keyStore, userKeyAlias, uid,
- keyCharacteristics);
- } else {
- throw new UnrecoverableKeyException("Key algorithm unknown");
- }
+ return 0;
}
/**
@@ -434,13 +88,9 @@
@NonNull
public static java.security.KeyStore getKeyStoreForUid(int uid)
throws KeyStoreException, NoSuchProviderException {
- final java.security.KeyStore.LoadStoreParameter loadParameter;
- if (android.security.keystore2.AndroidKeyStoreProvider.isInstalled()) {
- loadParameter = new android.security.keystore2.AndroidKeyStoreLoadStoreParameter(
- KeyProperties.legacyUidToNamespace(uid));
- } else {
- loadParameter = new AndroidKeyStoreLoadStoreParameter(uid);
- }
+ final java.security.KeyStore.LoadStoreParameter loadParameter =
+ new android.security.keystore2.AndroidKeyStoreLoadStoreParameter(
+ KeyProperties.legacyUidToNamespace(uid));
java.security.KeyStore result = java.security.KeyStore.getInstance(PROVIDER_NAME);
try {
result.load(loadParameter);
diff --git a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
deleted file mode 100644
index 4194780..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStorePublicKey.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import java.security.PublicKey;
-import java.util.Arrays;
-
-/**
- * {@link PublicKey} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStorePublicKey extends AndroidKeyStoreKey implements PublicKey {
-
- private final byte[] mEncoded;
-
- public AndroidKeyStorePublicKey(String alias, int uid, String algorithm, byte[] x509EncodedForm) {
- super(alias, uid, algorithm);
- mEncoded = ArrayUtils.cloneIfNotEmpty(x509EncodedForm);
- }
-
- @Override
- public String getFormat() {
- return "X.509";
- }
-
- @Override
- public byte[] getEncoded() {
- return ArrayUtils.cloneIfNotEmpty(mEncoded);
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = super.hashCode();
- result = prime * result + Arrays.hashCode(mEncoded);
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj) {
- return true;
- }
- if (!super.equals(obj)) {
- return false;
- }
- if (getClass() != obj.getClass()) {
- return false;
- }
- AndroidKeyStorePublicKey other = (AndroidKeyStorePublicKey) obj;
- if (!Arrays.equals(mEncoded, other.mEncoded)) {
- return false;
- }
- return true;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
deleted file mode 100644
index 2ae68fa..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSACipherSpi.java
+++ /dev/null
@@ -1,515 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.security.spec.MGF1ParameterSpec;
-
-import javax.crypto.Cipher;
-import javax.crypto.CipherSpi;
-import javax.crypto.spec.OAEPParameterSpec;
-import javax.crypto.spec.PSource;
-
-/**
- * Base class for {@link CipherSpi} providing Android KeyStore backed RSA encryption/decryption.
- *
- * @hide
- */
-abstract class AndroidKeyStoreRSACipherSpi extends AndroidKeyStoreCipherSpiBase {
-
- /**
- * Raw RSA cipher without any padding.
- */
- public static final class NoPadding extends AndroidKeyStoreRSACipherSpi {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
-
- @Override
- protected boolean adjustConfigForEncryptingWithPrivateKey() {
- // RSA encryption with no padding using private key is a way to implement raw RSA
- // signatures which JCA does not expose via Signature. We thus have to support this.
- setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
- return true;
- }
-
- @Override
- protected void initAlgorithmSpecificParameters() throws InvalidKeyException {}
-
- @Override
- protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException {
- if (params != null) {
- throw new InvalidAlgorithmParameterException(
- "Unexpected parameters: " + params + ". No parameters supported");
- }
- }
-
- @Override
- protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params)
- throws InvalidAlgorithmParameterException {
-
- if (params != null) {
- throw new InvalidAlgorithmParameterException(
- "Unexpected parameters: " + params + ". No parameters supported");
- }
- }
-
- @Override
- protected AlgorithmParameters engineGetParameters() {
- return null;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForBegin() {
- return 0;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForFinish() {
- return 0;
- }
- }
-
- /**
- * RSA cipher with PKCS#1 v1.5 encryption padding.
- */
- public static final class PKCS1Padding extends AndroidKeyStoreRSACipherSpi {
- public PKCS1Padding() {
- super(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- }
-
- @Override
- protected boolean adjustConfigForEncryptingWithPrivateKey() {
- // RSA encryption with PCKS#1 padding using private key is a way to implement RSA
- // signatures with PKCS#1 padding. We have to support this for legacy reasons.
- setKeymasterPurposeOverride(KeymasterDefs.KM_PURPOSE_SIGN);
- setKeymasterPaddingOverride(KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
- return true;
- }
-
- @Override
- protected void initAlgorithmSpecificParameters() throws InvalidKeyException {}
-
- @Override
- protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException {
- if (params != null) {
- throw new InvalidAlgorithmParameterException(
- "Unexpected parameters: " + params + ". No parameters supported");
- }
- }
-
- @Override
- protected void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params)
- throws InvalidAlgorithmParameterException {
-
- if (params != null) {
- throw new InvalidAlgorithmParameterException(
- "Unexpected parameters: " + params + ". No parameters supported");
- }
- }
-
- @Override
- protected AlgorithmParameters engineGetParameters() {
- return null;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForBegin() {
- return 0;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForFinish() {
- return (isEncrypting()) ? getModulusSizeBytes() : 0;
- }
- }
-
- /**
- * RSA cipher with OAEP encryption padding. Only SHA-1 based MGF1 is supported as MGF.
- */
- abstract static class OAEPWithMGF1Padding extends AndroidKeyStoreRSACipherSpi {
-
- private static final String MGF_ALGORITGM_MGF1 = "MGF1";
-
- private int mKeymasterDigest = -1;
- private int mDigestOutputSizeBytes;
-
- OAEPWithMGF1Padding(int keymasterDigest) {
- super(KeymasterDefs.KM_PAD_RSA_OAEP);
- mKeymasterDigest = keymasterDigest;
- mDigestOutputSizeBytes =
- (KeymasterUtils.getDigestOutputSizeBits(keymasterDigest) + 7) / 8;
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters() throws InvalidKeyException {}
-
- @Override
- protected final void initAlgorithmSpecificParameters(
- @Nullable AlgorithmParameterSpec params) throws InvalidAlgorithmParameterException {
- if (params == null) {
- return;
- }
-
- if (!(params instanceof OAEPParameterSpec)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported parameter spec: " + params
- + ". Only OAEPParameterSpec supported");
- }
- OAEPParameterSpec spec = (OAEPParameterSpec) params;
- if (!MGF_ALGORITGM_MGF1.equalsIgnoreCase(spec.getMGFAlgorithm())) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported MGF: " + spec.getMGFAlgorithm()
- + ". Only " + MGF_ALGORITGM_MGF1 + " supported");
- }
- String jcaDigest = spec.getDigestAlgorithm();
- int keymasterDigest;
- try {
- keymasterDigest = KeyProperties.Digest.toKeymaster(jcaDigest);
- } catch (IllegalArgumentException e) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported digest: " + jcaDigest, e);
- }
- switch (keymasterDigest) {
- case KeymasterDefs.KM_DIGEST_SHA1:
- case KeymasterDefs.KM_DIGEST_SHA_2_224:
- case KeymasterDefs.KM_DIGEST_SHA_2_256:
- case KeymasterDefs.KM_DIGEST_SHA_2_384:
- case KeymasterDefs.KM_DIGEST_SHA_2_512:
- // Permitted.
- break;
- default:
- throw new InvalidAlgorithmParameterException(
- "Unsupported digest: " + jcaDigest);
- }
- AlgorithmParameterSpec mgfParams = spec.getMGFParameters();
- if (mgfParams == null) {
- throw new InvalidAlgorithmParameterException("MGF parameters must be provided");
- }
- // Check whether MGF parameters match the OAEPParameterSpec
- if (!(mgfParams instanceof MGF1ParameterSpec)) {
- throw new InvalidAlgorithmParameterException("Unsupported MGF parameters"
- + ": " + mgfParams + ". Only MGF1ParameterSpec supported");
- }
- MGF1ParameterSpec mgfSpec = (MGF1ParameterSpec) mgfParams;
- String mgf1JcaDigest = mgfSpec.getDigestAlgorithm();
- if (!KeyProperties.DIGEST_SHA1.equalsIgnoreCase(mgf1JcaDigest)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported MGF1 digest: " + mgf1JcaDigest
- + ". Only " + KeyProperties.DIGEST_SHA1 + " supported");
- }
- PSource pSource = spec.getPSource();
- if (!(pSource instanceof PSource.PSpecified)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported source of encoding input P: " + pSource
- + ". Only pSpecifiedEmpty (PSource.PSpecified.DEFAULT) supported");
- }
- PSource.PSpecified pSourceSpecified = (PSource.PSpecified) pSource;
- byte[] pSourceValue = pSourceSpecified.getValue();
- if ((pSourceValue != null) && (pSourceValue.length > 0)) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported source of encoding input P: " + pSource
- + ". Only pSpecifiedEmpty (PSource.PSpecified.DEFAULT) supported");
- }
- mKeymasterDigest = keymasterDigest;
- mDigestOutputSizeBytes =
- (KeymasterUtils.getDigestOutputSizeBits(keymasterDigest) + 7) / 8;
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters(@Nullable AlgorithmParameters params)
- throws InvalidAlgorithmParameterException {
- if (params == null) {
- return;
- }
-
- OAEPParameterSpec spec;
- try {
- spec = params.getParameterSpec(OAEPParameterSpec.class);
- } catch (InvalidParameterSpecException e) {
- throw new InvalidAlgorithmParameterException("OAEP parameters required"
- + ", but not found in parameters: " + params, e);
- }
- if (spec == null) {
- throw new InvalidAlgorithmParameterException("OAEP parameters required"
- + ", but not provided in parameters: " + params);
- }
- initAlgorithmSpecificParameters(spec);
- }
-
- @Override
- protected final AlgorithmParameters engineGetParameters() {
- OAEPParameterSpec spec =
- new OAEPParameterSpec(
- KeyProperties.Digest.fromKeymaster(mKeymasterDigest),
- MGF_ALGORITGM_MGF1,
- MGF1ParameterSpec.SHA1,
- PSource.PSpecified.DEFAULT);
- try {
- AlgorithmParameters params = AlgorithmParameters.getInstance("OAEP");
- params.init(spec);
- return params;
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain OAEP AlgorithmParameters", e);
- } catch (InvalidParameterSpecException e) {
- throw new ProviderException(
- "Failed to initialize OAEP AlgorithmParameters with an IV",
- e);
- }
- }
-
- @Override
- protected final void addAlgorithmSpecificParametersToBegin(
- KeymasterArguments keymasterArgs) {
- super.addAlgorithmSpecificParametersToBegin(keymasterArgs);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
- }
-
- @Override
- protected final void loadAlgorithmSpecificParametersFromBeginResult(
- @NonNull KeymasterArguments keymasterArgs) {
- super.loadAlgorithmSpecificParametersFromBeginResult(keymasterArgs);
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForBegin() {
- return 0;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForFinish() {
- return (isEncrypting()) ? mDigestOutputSizeBytes : 0;
- }
- }
-
- public static class OAEPWithSHA1AndMGF1Padding extends OAEPWithMGF1Padding {
- public OAEPWithSHA1AndMGF1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA1);
- }
- }
-
- public static class OAEPWithSHA224AndMGF1Padding extends OAEPWithMGF1Padding {
- public OAEPWithSHA224AndMGF1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_224);
- }
- }
-
- public static class OAEPWithSHA256AndMGF1Padding extends OAEPWithMGF1Padding {
- public OAEPWithSHA256AndMGF1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_256);
- }
- }
-
- public static class OAEPWithSHA384AndMGF1Padding extends OAEPWithMGF1Padding {
- public OAEPWithSHA384AndMGF1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_384);
- }
- }
-
- public static class OAEPWithSHA512AndMGF1Padding extends OAEPWithMGF1Padding {
- public OAEPWithSHA512AndMGF1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- private final int mKeymasterPadding;
- private int mKeymasterPaddingOverride;
-
- private int mModulusSizeBytes = -1;
-
- AndroidKeyStoreRSACipherSpi(int keymasterPadding) {
- mKeymasterPadding = keymasterPadding;
- }
-
- @Override
- protected final void initKey(int opmode, Key key) throws InvalidKeyException {
- if (key == null) {
- throw new InvalidKeyException("Unsupported key: null");
- }
- if (!KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(key.getAlgorithm())) {
- throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm()
- + ". Only " + KeyProperties.KEY_ALGORITHM_RSA + " supported");
- }
- AndroidKeyStoreKey keystoreKey;
- if (key instanceof AndroidKeyStorePrivateKey) {
- keystoreKey = (AndroidKeyStoreKey) key;
- } else if (key instanceof AndroidKeyStorePublicKey) {
- keystoreKey = (AndroidKeyStoreKey) key;
- } else {
- throw new InvalidKeyException("Unsupported key type: " + key);
- }
-
- if (keystoreKey instanceof PrivateKey) {
- // Private key
- switch (opmode) {
- case Cipher.DECRYPT_MODE:
- case Cipher.UNWRAP_MODE:
- // Permitted
- break;
- case Cipher.ENCRYPT_MODE:
- case Cipher.WRAP_MODE:
- if (!adjustConfigForEncryptingWithPrivateKey()) {
- throw new InvalidKeyException(
- "RSA private keys cannot be used with " + opmodeToString(opmode)
- + " and padding "
- + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding)
- + ". Only RSA public keys supported for this mode");
- }
- break;
- default:
- throw new InvalidKeyException(
- "RSA private keys cannot be used with opmode: " + opmode);
- }
- } else {
- // Public key
- switch (opmode) {
- case Cipher.ENCRYPT_MODE:
- case Cipher.WRAP_MODE:
- // Permitted
- break;
- case Cipher.DECRYPT_MODE:
- case Cipher.UNWRAP_MODE:
- throw new InvalidKeyException(
- "RSA public keys cannot be used with " + opmodeToString(opmode)
- + " and padding "
- + KeyProperties.EncryptionPadding.fromKeymaster(mKeymasterPadding)
- + ". Only RSA private keys supported for this opmode.");
- // break;
- default:
- throw new InvalidKeyException(
- "RSA public keys cannot be used with " + opmodeToString(opmode));
- }
- }
-
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- int errorCode = getKeyStore().getKeyCharacteristics(
- keystoreKey.getAlias(), null, null, keystoreKey.getUid(), keyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- throw getKeyStore().getInvalidKeyException(
- keystoreKey.getAlias(), keystoreKey.getUid(), errorCode);
- }
- long keySizeBits = keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
- if (keySizeBits == -1) {
- throw new InvalidKeyException("Size of key not known");
- } else if (keySizeBits > Integer.MAX_VALUE) {
- throw new InvalidKeyException("Key too large: " + keySizeBits + " bits");
- }
- mModulusSizeBytes = (int) ((keySizeBits + 7) / 8);
-
- setKey(keystoreKey);
- }
-
- /**
- * Adjusts the configuration of this cipher for encrypting using the private key.
- *
- * <p>The default implementation does nothing and refuses to adjust the configuration.
- *
- * @return {@code true} if the configuration has been adjusted, {@code false} if encrypting
- * using private key is not permitted for this cipher.
- */
- protected boolean adjustConfigForEncryptingWithPrivateKey() {
- return false;
- }
-
- @Override
- protected final void resetAll() {
- mModulusSizeBytes = -1;
- mKeymasterPaddingOverride = -1;
- super.resetAll();
- }
-
- @Override
- protected final void resetWhilePreservingInitState() {
- super.resetWhilePreservingInitState();
- }
-
- @Override
- protected void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs) {
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
- int keymasterPadding = getKeymasterPaddingOverride();
- if (keymasterPadding == -1) {
- keymasterPadding = mKeymasterPadding;
- }
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, keymasterPadding);
- int purposeOverride = getKeymasterPurposeOverride();
- if ((purposeOverride != -1)
- && ((purposeOverride == KeymasterDefs.KM_PURPOSE_SIGN)
- || (purposeOverride == KeymasterDefs.KM_PURPOSE_VERIFY))) {
- // Keymaster sign/verify requires digest to be specified. For raw sign/verify it's NONE.
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_NONE);
- }
- }
-
- @Override
- protected void loadAlgorithmSpecificParametersFromBeginResult(
- @NonNull KeymasterArguments keymasterArgs) {
- }
-
- @Override
- protected final int engineGetBlockSize() {
- // Not a block cipher, according to the RI
- return 0;
- }
-
- @Override
- protected final byte[] engineGetIV() {
- // IV never used
- return null;
- }
-
- @Override
- protected final int engineGetOutputSize(int inputLen) {
- return getModulusSizeBytes();
- }
-
- protected final int getModulusSizeBytes() {
- if (mModulusSizeBytes == -1) {
- throw new IllegalStateException("Not initialized");
- }
- return mModulusSizeBytes;
- }
-
- /**
- * Overrides the default padding of the crypto operation.
- */
- protected final void setKeymasterPaddingOverride(int keymasterPadding) {
- mKeymasterPaddingOverride = keymasterPadding;
- }
-
- protected final int getKeymasterPaddingOverride() {
- return mKeymasterPaddingOverride;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
deleted file mode 100644
index adb3922..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPrivateKey.java
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import java.math.BigInteger;
-import java.security.PrivateKey;
-import java.security.interfaces.RSAKey;
-
-/**
- * RSA private key (instance of {@link PrivateKey} and {@link RSAKey}) backed by keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreRSAPrivateKey extends AndroidKeyStorePrivateKey implements RSAKey {
-
- private final BigInteger mModulus;
-
- public AndroidKeyStoreRSAPrivateKey(String alias, int uid, BigInteger modulus) {
- super(alias, uid, KeyProperties.KEY_ALGORITHM_RSA);
- mModulus = modulus;
- }
-
- @Override
- public BigInteger getModulus() {
- return mModulus;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
deleted file mode 100644
index d85aace..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSAPublicKey.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import java.math.BigInteger;
-import java.security.interfaces.RSAPublicKey;
-
-/**
- * {@link RSAPublicKey} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreRSAPublicKey extends AndroidKeyStorePublicKey implements RSAPublicKey {
- private final BigInteger mModulus;
- private final BigInteger mPublicExponent;
-
- public AndroidKeyStoreRSAPublicKey(String alias, int uid, byte[] x509EncodedForm, BigInteger modulus,
- BigInteger publicExponent) {
- super(alias, uid, KeyProperties.KEY_ALGORITHM_RSA, x509EncodedForm);
- mModulus = modulus;
- mPublicExponent = publicExponent;
- }
-
- public AndroidKeyStoreRSAPublicKey(String alias, int uid, RSAPublicKey info) {
- this(alias, uid, info.getEncoded(), info.getModulus(), info.getPublicExponent());
- if (!"X.509".equalsIgnoreCase(info.getFormat())) {
- throw new IllegalArgumentException(
- "Unsupported key export format: " + info.getFormat());
- }
- }
-
- @Override
- public BigInteger getModulus() {
- return mModulus;
- }
-
- @Override
- public BigInteger getPublicExponent() {
- return mPublicExponent;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java
deleted file mode 100644
index ecfc97e..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreRSASignatureSpi.java
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.annotation.NonNull;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.InvalidKeyException;
-import java.security.SignatureSpi;
-
-/**
- * Base class for {@link SignatureSpi} providing Android KeyStore backed RSA signatures.
- *
- * @hide
- */
-abstract class AndroidKeyStoreRSASignatureSpi extends AndroidKeyStoreSignatureSpiBase {
-
- abstract static class PKCS1Padding extends AndroidKeyStoreRSASignatureSpi {
- PKCS1Padding(int keymasterDigest) {
- super(keymasterDigest, KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_SIGN);
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForSign() {
- // No entropy required for this deterministic signature scheme.
- return 0;
- }
- }
-
- public static final class NONEWithPKCS1Padding extends PKCS1Padding {
- public NONEWithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_NONE);
- }
- }
-
- public static final class MD5WithPKCS1Padding extends PKCS1Padding {
- public MD5WithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_MD5);
- }
- }
-
- public static final class SHA1WithPKCS1Padding extends PKCS1Padding {
- public SHA1WithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA1);
- }
- }
-
- public static final class SHA224WithPKCS1Padding extends PKCS1Padding {
- public SHA224WithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_224);
- }
- }
-
- public static final class SHA256WithPKCS1Padding extends PKCS1Padding {
- public SHA256WithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_256);
- }
- }
-
- public static final class SHA384WithPKCS1Padding extends PKCS1Padding {
- public SHA384WithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_384);
- }
- }
-
- public static final class SHA512WithPKCS1Padding extends PKCS1Padding {
- public SHA512WithPKCS1Padding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- abstract static class PSSPadding extends AndroidKeyStoreRSASignatureSpi {
- private static final int SALT_LENGTH_BYTES = 20;
-
- PSSPadding(int keymasterDigest) {
- super(keymasterDigest, KeymasterDefs.KM_PAD_RSA_PSS);
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForSign() {
- return SALT_LENGTH_BYTES;
- }
- }
-
- public static final class SHA1WithPSSPadding extends PSSPadding {
- public SHA1WithPSSPadding() {
- super(KeymasterDefs.KM_DIGEST_SHA1);
- }
- }
-
- public static final class SHA224WithPSSPadding extends PSSPadding {
- public SHA224WithPSSPadding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_224);
- }
- }
-
- public static final class SHA256WithPSSPadding extends PSSPadding {
- public SHA256WithPSSPadding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_256);
- }
- }
-
- public static final class SHA384WithPSSPadding extends PSSPadding {
- public SHA384WithPSSPadding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_384);
- }
- }
-
- public static final class SHA512WithPSSPadding extends PSSPadding {
- public SHA512WithPSSPadding() {
- super(KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- private final int mKeymasterDigest;
- private final int mKeymasterPadding;
-
- AndroidKeyStoreRSASignatureSpi(int keymasterDigest, int keymasterPadding) {
- mKeymasterDigest = keymasterDigest;
- mKeymasterPadding = keymasterPadding;
- }
-
- @Override
- protected final void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
- if (!KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(key.getAlgorithm())) {
- throw new InvalidKeyException("Unsupported key algorithm: " + key.getAlgorithm()
- + ". Only" + KeyProperties.KEY_ALGORITHM_RSA + " supported");
- }
- super.initKey(key);
- }
-
- @Override
- protected final void resetAll() {
- super.resetAll();
- }
-
- @Override
- protected final void resetWhilePreservingInitState() {
- super.resetWhilePreservingInitState();
- }
-
- @Override
- protected final void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs) {
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_DIGEST, mKeymasterDigest);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
deleted file mode 100644
index b8e6af7..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKey.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import javax.crypto.SecretKey;
-
-/**
- * {@link SecretKey} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreSecretKey extends AndroidKeyStoreKey implements SecretKey {
-
- public AndroidKeyStoreSecretKey(String alias, int uid, String algorithm) {
- super(alias, uid, algorithm);
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
deleted file mode 100644
index d2678c7..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSecretKeyFactorySpi.java
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.security.Credentials;
-import android.security.GateKeeper;
-import android.security.KeyStore;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterDefs;
-
-import java.math.BigInteger;
-import java.security.InvalidKeyException;
-import java.security.ProviderException;
-import java.security.spec.InvalidKeySpecException;
-import java.security.spec.KeySpec;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-import javax.crypto.SecretKey;
-import javax.crypto.SecretKeyFactorySpi;
-import javax.crypto.spec.SecretKeySpec;
-
-/**
- * {@link SecretKeyFactorySpi} backed by Android Keystore.
- *
- * @hide
- */
-public class AndroidKeyStoreSecretKeyFactorySpi extends SecretKeyFactorySpi {
-
- private final KeyStore mKeyStore = KeyStore.getInstance();
-
- @Override
- protected KeySpec engineGetKeySpec(SecretKey key,
- @SuppressWarnings("rawtypes") Class keySpecClass) throws InvalidKeySpecException {
- if (keySpecClass == null) {
- throw new InvalidKeySpecException("keySpecClass == null");
- }
- if (!(key instanceof AndroidKeyStoreSecretKey)) {
- throw new InvalidKeySpecException("Only Android KeyStore secret keys supported: " +
- ((key != null) ? key.getClass().getName() : "null"));
- }
- if (SecretKeySpec.class.isAssignableFrom(keySpecClass)) {
- throw new InvalidKeySpecException(
- "Key material export of Android KeyStore keys is not supported");
- }
- if (!KeyInfo.class.equals(keySpecClass)) {
- throw new InvalidKeySpecException("Unsupported key spec: " + keySpecClass.getName());
- }
- AndroidKeyStoreKey keystoreKey = (AndroidKeyStoreKey) key;
- String keyAliasInKeystore = keystoreKey.getAlias();
- String entryAlias;
- if (keyAliasInKeystore.startsWith(Credentials.USER_PRIVATE_KEY)) {
- entryAlias = keyAliasInKeystore.substring(Credentials.USER_PRIVATE_KEY.length());
- } else if (keyAliasInKeystore.startsWith(Credentials.USER_SECRET_KEY)){
- // key has legacy prefix
- entryAlias = keyAliasInKeystore.substring(Credentials.USER_SECRET_KEY.length());
- } else {
- throw new InvalidKeySpecException("Invalid key alias: " + keyAliasInKeystore);
- }
-
- return getKeyInfo(mKeyStore, entryAlias, keyAliasInKeystore, keystoreKey.getUid());
- }
-
- static KeyInfo getKeyInfo(KeyStore keyStore, String entryAlias, String keyAliasInKeystore,
- int keyUid) {
- KeyCharacteristics keyCharacteristics = new KeyCharacteristics();
- int errorCode = keyStore.getKeyCharacteristics(
- keyAliasInKeystore, null, null, keyUid, keyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new ProviderException("Failed to obtain information about key."
- + " Keystore error: " + errorCode);
- }
-
- boolean insideSecureHardware;
- @KeyProperties.OriginEnum int origin;
- int keySize;
- @KeyProperties.PurposeEnum int purposes;
- String[] encryptionPaddings;
- String[] signaturePaddings;
- @KeyProperties.DigestEnum String[] digests;
- @KeyProperties.BlockModeEnum String[] blockModes;
- int keymasterSwEnforcedUserAuthenticators;
- int keymasterHwEnforcedUserAuthenticators;
- List<BigInteger> keymasterSecureUserIds;
- try {
- if (keyCharacteristics.hwEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
- insideSecureHardware = true;
- origin = KeyProperties.Origin.fromKeymaster(
- keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_ORIGIN, -1));
- } else if (keyCharacteristics.swEnforced.containsTag(KeymasterDefs.KM_TAG_ORIGIN)) {
- insideSecureHardware = false;
- origin = KeyProperties.Origin.fromKeymaster(
- keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_ORIGIN, -1));
- } else {
- throw new ProviderException("Key origin not available");
- }
- long keySizeUnsigned =
- keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_KEY_SIZE, -1);
- if (keySizeUnsigned == -1) {
- throw new ProviderException("Key size not available");
- } else if (keySizeUnsigned > Integer.MAX_VALUE) {
- throw new ProviderException("Key too large: " + keySizeUnsigned + " bits");
- }
- keySize = (int) keySizeUnsigned;
- purposes = KeyProperties.Purpose.allFromKeymaster(
- keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_PURPOSE));
-
- List<String> encryptionPaddingsList = new ArrayList<String>();
- List<String> signaturePaddingsList = new ArrayList<String>();
- // Keymaster stores both types of paddings in the same array -- we split it into two.
- for (int keymasterPadding : keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_PADDING)) {
- try {
- @KeyProperties.EncryptionPaddingEnum String jcaPadding =
- KeyProperties.EncryptionPadding.fromKeymaster(keymasterPadding);
- encryptionPaddingsList.add(jcaPadding);
- } catch (IllegalArgumentException e) {
- try {
- @KeyProperties.SignaturePaddingEnum String padding =
- KeyProperties.SignaturePadding.fromKeymaster(keymasterPadding);
- signaturePaddingsList.add(padding);
- } catch (IllegalArgumentException e2) {
- throw new ProviderException(
- "Unsupported encryption padding: " + keymasterPadding);
- }
- }
-
- }
- encryptionPaddings =
- encryptionPaddingsList.toArray(new String[encryptionPaddingsList.size()]);
- signaturePaddings =
- signaturePaddingsList.toArray(new String[signaturePaddingsList.size()]);
-
- digests = KeyProperties.Digest.allFromKeymaster(
- keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_DIGEST));
- blockModes = KeyProperties.BlockMode.allFromKeymaster(
- keyCharacteristics.getEnums(KeymasterDefs.KM_TAG_BLOCK_MODE));
- keymasterSwEnforcedUserAuthenticators =
- keyCharacteristics.swEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
- keymasterHwEnforcedUserAuthenticators =
- keyCharacteristics.hwEnforced.getEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, 0);
- keymasterSecureUserIds =
- keyCharacteristics.getUnsignedLongs(KeymasterDefs.KM_TAG_USER_SECURE_ID);
- } catch (IllegalArgumentException e) {
- throw new ProviderException("Unsupported key characteristic", e);
- }
-
- Date keyValidityStart = keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ACTIVE_DATETIME);
- Date keyValidityForOriginationEnd =
- keyCharacteristics.getDate(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME);
- Date keyValidityForConsumptionEnd =
- keyCharacteristics.getDate(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME);
- boolean userAuthenticationRequired =
- !keyCharacteristics.getBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
- long userAuthenticationValidityDurationSeconds =
- keyCharacteristics.getUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT, 0);
- if (userAuthenticationValidityDurationSeconds > Integer.MAX_VALUE) {
- throw new ProviderException("User authentication timeout validity too long: "
- + userAuthenticationValidityDurationSeconds + " seconds");
- }
- boolean userAuthenticationRequirementEnforcedBySecureHardware = (userAuthenticationRequired)
- && (keymasterHwEnforcedUserAuthenticators != 0)
- && (keymasterSwEnforcedUserAuthenticators == 0);
- boolean userAuthenticationValidWhileOnBody =
- keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
- boolean trustedUserPresenceRequired =
- keyCharacteristics.hwEnforced.getBoolean(
- KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
-
- boolean invalidatedByBiometricEnrollment = false;
- if (keymasterSwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_BIOMETRIC
- || keymasterHwEnforcedUserAuthenticators == KeymasterDefs.HW_AUTH_BIOMETRIC) {
- // Fingerprint-only key; will be invalidated if the root SID isn't in the SID list.
- invalidatedByBiometricEnrollment = keymasterSecureUserIds != null
- && !keymasterSecureUserIds.isEmpty()
- && !keymasterSecureUserIds.contains(getGateKeeperSecureUserId());
- }
-
- boolean userConfirmationRequired = keyCharacteristics.hwEnforced.getBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
-
- return new KeyInfo(entryAlias,
- insideSecureHardware,
- origin,
- keySize,
- keyValidityStart,
- keyValidityForOriginationEnd,
- keyValidityForConsumptionEnd,
- purposes,
- encryptionPaddings,
- signaturePaddings,
- digests,
- blockModes,
- userAuthenticationRequired,
- (int) userAuthenticationValidityDurationSeconds,
- keymasterHwEnforcedUserAuthenticators,
- userAuthenticationRequirementEnforcedBySecureHardware,
- userAuthenticationValidWhileOnBody,
- trustedUserPresenceRequired,
- invalidatedByBiometricEnrollment,
- userConfirmationRequired,
- // Keystore 1.0 does not tell us the exact security level of the key
- // so we report an unknown but secure security level.
- insideSecureHardware ? KeyProperties.SECURITY_LEVEL_UNKNOWN_SECURE
- : KeyProperties.SECURITY_LEVEL_SOFTWARE,
- KeyProperties.UNRESTRICTED_USAGE_COUNT);
- }
-
- private static BigInteger getGateKeeperSecureUserId() throws ProviderException {
- try {
- return BigInteger.valueOf(GateKeeper.getSecureUserId());
- } catch (IllegalStateException e) {
- throw new ProviderException("Failed to get GateKeeper secure user ID", e);
- }
- }
-
- @Override
- protected SecretKey engineGenerateSecret(KeySpec keySpec) throws InvalidKeySpecException {
- throw new InvalidKeySpecException(
- "To generate secret key in Android Keystore, use KeyGenerator initialized with "
- + KeyGenParameterSpec.class.getName());
- }
-
- @Override
- protected SecretKey engineTranslateKey(SecretKey key) throws InvalidKeyException {
- if (key == null) {
- throw new InvalidKeyException("key == null");
- } else if (!(key instanceof AndroidKeyStoreSecretKey)) {
- throw new InvalidKeyException(
- "To import a secret key into Android Keystore, use KeyStore.setEntry");
- }
-
- return key;
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java b/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
deleted file mode 100644
index da47b6b..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSignatureSpiBase.java
+++ /dev/null
@@ -1,431 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.annotation.CallSuper;
-import android.annotation.NonNull;
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-
-import libcore.util.EmptyArray;
-
-import java.nio.ByteBuffer;
-import java.security.InvalidKeyException;
-import java.security.InvalidParameterException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.SecureRandom;
-import java.security.SignatureException;
-import java.security.SignatureSpi;
-
-/**
- * Base class for {@link SignatureSpi} implementations of Android KeyStore backed ciphers.
- *
- * @hide
- */
-abstract class AndroidKeyStoreSignatureSpiBase extends SignatureSpi
- implements KeyStoreCryptoOperation {
- private final KeyStore mKeyStore;
-
- // Fields below are populated by SignatureSpi.engineInitSign/engineInitVerify and KeyStore.begin
- // and should be preserved after SignatureSpi.engineSign/engineVerify finishes.
- private boolean mSigning;
- private AndroidKeyStoreKey mKey;
-
- /**
- * Token referencing this operation inside keystore service. It is initialized by
- * {@code engineInitSign}/{@code engineInitVerify} and is invalidated when
- * {@code engineSign}/{@code engineVerify} succeeds and on some error conditions in between.
- */
- private IBinder mOperationToken;
- private long mOperationHandle;
- private KeyStoreCryptoOperationStreamer mMessageStreamer;
-
- /**
- * Encountered exception which could not be immediately thrown because it was encountered inside
- * a method that does not throw checked exception. This exception will be thrown from
- * {@code engineSign} or {@code engineVerify}. Once such an exception is encountered,
- * {@code engineUpdate} starts ignoring input data.
- */
- private Exception mCachedException;
-
- AndroidKeyStoreSignatureSpiBase() {
- mKeyStore = KeyStore.getInstance();
- }
-
- @Override
- protected final void engineInitSign(PrivateKey key) throws InvalidKeyException {
- engineInitSign(key, null);
- }
-
- @Override
- protected final void engineInitSign(PrivateKey privateKey, SecureRandom random)
- throws InvalidKeyException {
- resetAll();
-
- boolean success = false;
- try {
- if (privateKey == null) {
- throw new InvalidKeyException("Unsupported key: null");
- }
- AndroidKeyStoreKey keystoreKey;
- if (privateKey instanceof AndroidKeyStorePrivateKey) {
- keystoreKey = (AndroidKeyStoreKey) privateKey;
- } else {
- throw new InvalidKeyException("Unsupported private key type: " + privateKey);
- }
- mSigning = true;
- initKey(keystoreKey);
- appRandom = random;
- ensureKeystoreOperationInitialized();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- @Override
- protected final void engineInitVerify(PublicKey publicKey) throws InvalidKeyException {
- resetAll();
-
- boolean success = false;
- try {
- if (publicKey == null) {
- throw new InvalidKeyException("Unsupported key: null");
- }
- AndroidKeyStoreKey keystoreKey;
- if (publicKey instanceof AndroidKeyStorePublicKey) {
- keystoreKey = (AndroidKeyStorePublicKey) publicKey;
- } else {
- throw new InvalidKeyException("Unsupported public key type: " + publicKey);
- }
- mSigning = false;
- initKey(keystoreKey);
- appRandom = null;
- ensureKeystoreOperationInitialized();
- success = true;
- } finally {
- if (!success) {
- resetAll();
- }
- }
- }
-
- /**
- * Configures this signature instance to use the provided key.
- *
- * @throws InvalidKeyException if the {@code key} is not suitable.
- */
- @CallSuper
- protected void initKey(AndroidKeyStoreKey key) throws InvalidKeyException {
- mKey = key;
- }
-
- /**
- * Resets this cipher to its pristine pre-init state. This must be equivalent to obtaining a new
- * cipher instance.
- *
- * <p>Subclasses storing additional state should override this method, reset the additional
- * state, and then chain to superclass.
- */
- @CallSuper
- protected void resetAll() {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mOperationToken = null;
- mKeyStore.abort(operationToken);
- }
- mSigning = false;
- mKey = null;
- appRandom = null;
- mOperationToken = null;
- mOperationHandle = 0;
- mMessageStreamer = null;
- mCachedException = null;
- }
-
- /**
- * Resets this cipher while preserving the initialized state. This must be equivalent to
- * rolling back the cipher's state to just after the most recent {@code engineInit} completed
- * successfully.
- *
- * <p>Subclasses storing additional post-init state should override this method, reset the
- * additional state, and then chain to superclass.
- */
- @CallSuper
- protected void resetWhilePreservingInitState() {
- IBinder operationToken = mOperationToken;
- if (operationToken != null) {
- mOperationToken = null;
- mKeyStore.abort(operationToken);
- }
- mOperationHandle = 0;
- mMessageStreamer = null;
- mCachedException = null;
- }
-
- private void ensureKeystoreOperationInitialized() throws InvalidKeyException {
- if (mMessageStreamer != null) {
- return;
- }
- if (mCachedException != null) {
- return;
- }
- if (mKey == null) {
- throw new IllegalStateException("Not initialized");
- }
-
- KeymasterArguments keymasterInputArgs = new KeymasterArguments();
- addAlgorithmSpecificParametersToBegin(keymasterInputArgs);
-
- OperationResult opResult = mKeyStore.begin(
- mKey.getAlias(),
- mSigning ? KeymasterDefs.KM_PURPOSE_SIGN : KeymasterDefs.KM_PURPOSE_VERIFY,
- true, // permit aborting this operation if keystore runs out of resources
- keymasterInputArgs,
- null, // no additional entropy for begin -- only finish might need some
- mKey.getUid());
- if (opResult == null) {
- throw new KeyStoreConnectException();
- }
-
- // Store operation token and handle regardless of the error code returned by KeyStore to
- // ensure that the operation gets aborted immediately if the code below throws an exception.
- mOperationToken = opResult.token;
- mOperationHandle = opResult.operationHandle;
-
- // If necessary, throw an exception due to KeyStore operation having failed.
- InvalidKeyException e = KeyStoreCryptoOperationUtils.getInvalidKeyExceptionForInit(
- mKeyStore, mKey, opResult.resultCode);
- if (e != null) {
- throw e;
- }
-
- if (mOperationToken == null) {
- throw new ProviderException("Keystore returned null operation token");
- }
- if (mOperationHandle == 0) {
- throw new ProviderException("Keystore returned invalid operation handle");
- }
-
- mMessageStreamer = createMainDataStreamer(mKeyStore, opResult.token);
- }
-
- /**
- * Creates a streamer which sends the message to be signed/verified into the provided KeyStore
- *
- * <p>This implementation returns a working streamer.
- */
- @NonNull
- protected KeyStoreCryptoOperationStreamer createMainDataStreamer(
- KeyStore keyStore, IBinder operationToken) {
- return new KeyStoreCryptoOperationChunkedStreamer(
- new KeyStoreCryptoOperationChunkedStreamer.MainDataStream(
- keyStore, operationToken));
- }
-
- @Override
- public final long getOperationHandle() {
- return mOperationHandle;
- }
-
- @Override
- protected final void engineUpdate(byte[] b, int off, int len) throws SignatureException {
- if (mCachedException != null) {
- throw new SignatureException(mCachedException);
- }
-
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException e) {
- throw new SignatureException(e);
- }
-
- if (len == 0) {
- return;
- }
-
- byte[] output;
- try {
- output = mMessageStreamer.update(b, off, len);
- } catch (KeyStoreException e) {
- throw new SignatureException(e);
- }
-
- if (output.length != 0) {
- throw new ProviderException(
- "Update operation unexpectedly produced output: " + output.length + " bytes");
- }
- }
-
- @Override
- protected final void engineUpdate(byte b) throws SignatureException {
- engineUpdate(new byte[] {b}, 0, 1);
- }
-
- @Override
- protected final void engineUpdate(ByteBuffer input) {
- byte[] b;
- int off;
- int len = input.remaining();
- if (input.hasArray()) {
- b = input.array();
- off = input.arrayOffset() + input.position();
- input.position(input.limit());
- } else {
- b = new byte[len];
- off = 0;
- input.get(b);
- }
-
- try {
- engineUpdate(b, off, len);
- } catch (SignatureException e) {
- mCachedException = e;
- }
- }
-
- @Override
- protected final int engineSign(byte[] out, int outOffset, int outLen)
- throws SignatureException {
- return super.engineSign(out, outOffset, outLen);
- }
-
- @Override
- protected final byte[] engineSign() throws SignatureException {
- if (mCachedException != null) {
- throw new SignatureException(mCachedException);
- }
-
- byte[] signature;
- try {
- ensureKeystoreOperationInitialized();
-
- byte[] additionalEntropy =
- KeyStoreCryptoOperationUtils.getRandomBytesToMixIntoKeystoreRng(
- appRandom, getAdditionalEntropyAmountForSign());
- signature = mMessageStreamer.doFinal(
- EmptyArray.BYTE, 0, 0,
- null, // no signature provided -- it'll be generated by this invocation
- additionalEntropy);
- } catch (InvalidKeyException | KeyStoreException e) {
- throw new SignatureException(e);
- }
-
- resetWhilePreservingInitState();
- return signature;
- }
-
- @Override
- protected final boolean engineVerify(byte[] signature) throws SignatureException {
- if (mCachedException != null) {
- throw new SignatureException(mCachedException);
- }
-
- try {
- ensureKeystoreOperationInitialized();
- } catch (InvalidKeyException e) {
- throw new SignatureException(e);
- }
-
- boolean verified;
- try {
- byte[] output = mMessageStreamer.doFinal(
- EmptyArray.BYTE, 0, 0,
- signature,
- null // no additional entropy needed -- verification is deterministic
- );
- if (output.length != 0) {
- throw new ProviderException(
- "Signature verification unexpected produced output: " + output.length
- + " bytes");
- }
- verified = true;
- } catch (KeyStoreException e) {
- switch (e.getErrorCode()) {
- case KeymasterDefs.KM_ERROR_VERIFICATION_FAILED:
- verified = false;
- break;
- default:
- throw new SignatureException(e);
- }
- }
-
- resetWhilePreservingInitState();
- return verified;
- }
-
- @Override
- protected final boolean engineVerify(byte[] sigBytes, int offset, int len)
- throws SignatureException {
- return engineVerify(ArrayUtils.subarray(sigBytes, offset, len));
- }
-
- @Deprecated
- @Override
- protected final Object engineGetParameter(String param) throws InvalidParameterException {
- throw new InvalidParameterException();
- }
-
- @Deprecated
- @Override
- protected final void engineSetParameter(String param, Object value)
- throws InvalidParameterException {
- throw new InvalidParameterException();
- }
-
- protected final KeyStore getKeyStore() {
- return mKeyStore;
- }
-
- /**
- * Returns {@code true} if this signature is initialized for signing, {@code false} if this
- * signature is initialized for verification.
- */
- protected final boolean isSigning() {
- return mSigning;
- }
-
- // The methods below need to be implemented by subclasses.
-
- /**
- * Returns the amount of additional entropy (in bytes) to be provided to the KeyStore's
- * {@code finish} operation when generating a signature.
- *
- * <p>This value should match (or exceed) the amount of Shannon entropy of the produced
- * signature assuming the key and the message are known. For example, for ECDSA signature this
- * should be the size of {@code R}, whereas for the RSA signature with PKCS#1 padding this
- * should be {@code 0}.
- */
- protected abstract int getAdditionalEntropyAmountForSign();
-
- /**
- * Invoked to add algorithm-specific parameters for the KeyStore's {@code begin} operation.
- *
- * @param keymasterArgs keystore/keymaster arguments to be populated with algorithm-specific
- * parameters.
- */
- protected abstract void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs);
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
deleted file mode 100644
index 51c4252..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ /dev/null
@@ -1,1112 +0,0 @@
-/*
- * Copyright (C) 2012 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.keystore;
-
-import android.security.Credentials;
-import android.security.GateKeeper;
-import android.security.KeyStore;
-import android.security.KeyStoreParameter;
-import android.security.keymaster.KeyCharacteristics;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keystore.KeyPermanentlyInvalidatedException;
-import android.security.keystore.KeyProperties;
-import android.security.keystore.KeyProtection;
-import android.security.keystore.SecureKeyImportUnavailableException;
-import android.security.keystore.WrappedKeyEntry;
-import android.util.Log;
-
-import libcore.util.EmptyArray;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.security.Key;
-import java.security.KeyStore.Entry;
-import java.security.KeyStore.LoadStoreParameter;
-import java.security.KeyStore.PrivateKeyEntry;
-import java.security.KeyStore.ProtectionParameter;
-import java.security.KeyStore.SecretKeyEntry;
-import java.security.KeyStoreException;
-import java.security.KeyStoreSpi;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.ProviderException;
-import java.security.PublicKey;
-import java.security.UnrecoverableKeyException;
-import java.security.cert.Certificate;
-import java.security.cert.CertificateEncodingException;
-import java.security.cert.CertificateException;
-import java.security.cert.CertificateFactory;
-import java.security.cert.X509Certificate;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.Enumeration;
-import java.util.HashSet;
-import java.util.Iterator;
-import java.util.Set;
-
-import javax.crypto.SecretKey;
-
-/**
- * A java.security.KeyStore interface for the Android KeyStore. An instance of
- * it can be created via the {@link java.security.KeyStore#getInstance(String)
- * KeyStore.getInstance("AndroidKeyStore")} interface. This returns a
- * java.security.KeyStore backed by this "AndroidKeyStore" implementation.
- * <p>
- * This is built on top of Android's keystore daemon. The convention of alias
- * use is:
- * <p>
- * PrivateKeyEntry will have a Credentials.USER_PRIVATE_KEY as the private key,
- * Credentials.USER_CERTIFICATE as the first certificate in the chain (the one
- * that corresponds to the private key), and then a Credentials.CA_CERTIFICATE
- * entry which will have the rest of the chain concatenated in BER format.
- * <p>
- * TrustedCertificateEntry will just have a Credentials.CA_CERTIFICATE entry
- * with a single certificate.
- *
- * @hide
- */
-public class AndroidKeyStoreSpi extends KeyStoreSpi {
- public static final String NAME = "AndroidKeyStore";
-
- private KeyStore mKeyStore;
- private int mUid = KeyStore.UID_SELF;
-
- @Override
- public Key engineGetKey(String alias, char[] password) throws NoSuchAlgorithmException,
- UnrecoverableKeyException {
- String userKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
- AndroidKeyStoreKey key;
- if (!mKeyStore.contains(userKeyAlias, mUid)) {
- // try legacy prefix for backward compatibility
- userKeyAlias = Credentials.USER_SECRET_KEY + alias;
- if (!mKeyStore.contains(userKeyAlias, mUid)) return null;
- }
- try {
- key = AndroidKeyStoreProvider.loadAndroidKeyStoreKeyFromKeystore(mKeyStore,
- userKeyAlias,
- mUid);
- } catch (KeyPermanentlyInvalidatedException e) {
- throw new UnrecoverableKeyException(e.getMessage());
- }
- return key;
- }
-
- @Override
- public Certificate[] engineGetCertificateChain(String alias) {
- if (alias == null) {
- throw new NullPointerException("alias == null");
- }
-
- final X509Certificate leaf = (X509Certificate) engineGetCertificate(alias);
- if (leaf == null) {
- return null;
- }
-
- final Certificate[] caList;
-
- // Suppress the key not found warning for this call. It seems that this error is exclusively
- // being thrown when there is a self signed certificate chain, so when the keystore service
- // attempts to query for the CA details, it obviously fails to find them and returns a
- // key not found exception. This is WAI, and throwing a stack trace here can be very
- // misleading since the trace is not clear.
- final byte[] caBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias,
- mUid,
- true /* suppressKeyNotFoundWarning */);
- if (caBytes != null) {
- final Collection<X509Certificate> caChain = toCertificates(caBytes);
-
- caList = new Certificate[caChain.size() + 1];
-
- final Iterator<X509Certificate> it = caChain.iterator();
- int i = 1;
- while (it.hasNext()) {
- caList[i++] = it.next();
- }
- } else {
- caList = new Certificate[1];
- }
-
- caList[0] = leaf;
-
- return caList;
- }
-
- @Override
- public Certificate engineGetCertificate(String alias) {
- if (alias == null) {
- throw new NullPointerException("alias == null");
- }
-
- byte[] encodedCert = mKeyStore.get(Credentials.USER_CERTIFICATE + alias, mUid);
- if (encodedCert != null) {
- return getCertificateForPrivateKeyEntry(alias, encodedCert);
- }
-
- encodedCert = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
- if (encodedCert != null) {
- return getCertificateForTrustedCertificateEntry(encodedCert);
- }
-
- // This entry/alias does not contain a certificate.
- return null;
- }
-
- private Certificate getCertificateForTrustedCertificateEntry(byte[] encodedCert) {
- // For this certificate there shouldn't be a private key in this KeyStore entry. Thus,
- // there's no need to wrap this certificate as opposed to the certificate associated with
- // a private key entry.
- return toCertificate(encodedCert);
- }
-
- private Certificate getCertificateForPrivateKeyEntry(String alias, byte[] encodedCert) {
- // All crypto algorithms offered by Android Keystore for its private keys must also
- // be offered for the corresponding public keys stored in the Android Keystore. The
- // complication is that the underlying keystore service operates only on full key pairs,
- // rather than just public keys or private keys. As a result, Android Keystore-backed
- // crypto can only be offered for public keys for which keystore contains the
- // corresponding private key. This is not the case for certificate-only entries (e.g.,
- // trusted certificates).
- //
- // getCertificate().getPublicKey() is the only way to obtain the public key
- // corresponding to the private key stored in the KeyStore. Thus, we need to make sure
- // that the returned public key points to the underlying key pair / private key
- // when available.
-
- X509Certificate cert = toCertificate(encodedCert);
- if (cert == null) {
- // Failed to parse the certificate.
- return null;
- }
-
- String privateKeyAlias = Credentials.USER_PRIVATE_KEY + alias;
- if (mKeyStore.contains(privateKeyAlias, mUid)) {
- // As expected, keystore contains the private key corresponding to this public key. Wrap
- // the certificate so that its getPublicKey method returns an Android Keystore
- // PublicKey. This key will delegate crypto operations involving this public key to
- // Android Keystore when higher-priority providers do not offer these crypto
- // operations for this key.
- return wrapIntoKeyStoreCertificate(privateKeyAlias, mUid, cert);
- } else {
- // This KeyStore entry/alias is supposed to contain the private key corresponding to
- // the public key in this certificate, but it does not for some reason. It's probably a
- // bug. Let other providers handle crypto operations involving the public key returned
- // by this certificate's getPublicKey.
- return cert;
- }
- }
-
- /**
- * Wraps the provided cerificate into {@link KeyStoreX509Certificate} so that the public key
- * returned by the certificate contains information about the alias of the private key in
- * keystore. This is needed so that Android Keystore crypto operations using public keys can
- * find out which key alias to use. These operations cannot work without an alias.
- */
- private static KeyStoreX509Certificate wrapIntoKeyStoreCertificate(
- String privateKeyAlias, int uid, X509Certificate certificate) {
- return (certificate != null)
- ? new KeyStoreX509Certificate(privateKeyAlias, uid, certificate) : null;
- }
-
- private static X509Certificate toCertificate(byte[] bytes) {
- try {
- final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- return (X509Certificate) certFactory.generateCertificate(
- new ByteArrayInputStream(bytes));
- } catch (CertificateException e) {
- Log.w(NAME, "Couldn't parse certificate in keystore", e);
- return null;
- }
- }
-
- @SuppressWarnings("unchecked")
- private static Collection<X509Certificate> toCertificates(byte[] bytes) {
- try {
- final CertificateFactory certFactory = CertificateFactory.getInstance("X.509");
- return (Collection<X509Certificate>) certFactory.generateCertificates(
- new ByteArrayInputStream(bytes));
- } catch (CertificateException e) {
- Log.w(NAME, "Couldn't parse certificates in keystore", e);
- return new ArrayList<X509Certificate>();
- }
- }
-
- private Date getModificationDate(String alias) {
- final long epochMillis = mKeyStore.getmtime(alias, mUid);
- if (epochMillis == -1L) {
- return null;
- }
-
- return new Date(epochMillis);
- }
-
- @Override
- public Date engineGetCreationDate(String alias) {
- if (alias == null) {
- throw new NullPointerException("alias == null");
- }
-
- Date d = getModificationDate(Credentials.USER_PRIVATE_KEY + alias);
- if (d != null) {
- return d;
- }
-
- d = getModificationDate(Credentials.USER_SECRET_KEY + alias);
- if (d != null) {
- return d;
- }
-
- d = getModificationDate(Credentials.USER_CERTIFICATE + alias);
- if (d != null) {
- return d;
- }
-
- return getModificationDate(Credentials.CA_CERTIFICATE + alias);
- }
-
- @Override
- public void engineSetKeyEntry(String alias, Key key, char[] password, Certificate[] chain)
- throws KeyStoreException {
- if ((password != null) && (password.length > 0)) {
- throw new KeyStoreException("entries cannot be protected with passwords");
- }
-
- if (key instanceof PrivateKey) {
- setPrivateKeyEntry(alias, (PrivateKey) key, chain, null);
- } else if (key instanceof SecretKey) {
- setSecretKeyEntry(alias, (SecretKey) key, null);
- } else {
- throw new KeyStoreException("Only PrivateKey and SecretKey are supported");
- }
- }
-
- private static KeyProtection getLegacyKeyProtectionParameter(PrivateKey key)
- throws KeyStoreException {
- String keyAlgorithm = key.getAlgorithm();
- KeyProtection.Builder specBuilder;
- if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(keyAlgorithm)) {
- specBuilder =
- new KeyProtection.Builder(
- KeyProperties.PURPOSE_SIGN | KeyProperties.PURPOSE_VERIFY);
- // Authorized to be used with any digest (including no digest).
- // MD5 was never offered for Android Keystore for ECDSA.
- specBuilder.setDigests(
- KeyProperties.DIGEST_NONE,
- KeyProperties.DIGEST_SHA1,
- KeyProperties.DIGEST_SHA224,
- KeyProperties.DIGEST_SHA256,
- KeyProperties.DIGEST_SHA384,
- KeyProperties.DIGEST_SHA512);
- } else if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(keyAlgorithm)) {
- specBuilder =
- new KeyProtection.Builder(
- KeyProperties.PURPOSE_ENCRYPT
- | KeyProperties.PURPOSE_DECRYPT
- | KeyProperties.PURPOSE_SIGN
- | KeyProperties.PURPOSE_VERIFY);
- // Authorized to be used with any digest (including no digest).
- specBuilder.setDigests(
- KeyProperties.DIGEST_NONE,
- KeyProperties.DIGEST_MD5,
- KeyProperties.DIGEST_SHA1,
- KeyProperties.DIGEST_SHA224,
- KeyProperties.DIGEST_SHA256,
- KeyProperties.DIGEST_SHA384,
- KeyProperties.DIGEST_SHA512);
- // Authorized to be used with any encryption and signature padding
- // schemes (including no padding).
- specBuilder.setEncryptionPaddings(
- KeyProperties.ENCRYPTION_PADDING_NONE,
- KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1,
- KeyProperties.ENCRYPTION_PADDING_RSA_OAEP);
- specBuilder.setSignaturePaddings(
- KeyProperties.SIGNATURE_PADDING_RSA_PKCS1,
- KeyProperties.SIGNATURE_PADDING_RSA_PSS);
- // Disable randomized encryption requirement to support encryption
- // padding NONE above.
- specBuilder.setRandomizedEncryptionRequired(false);
- } else {
- throw new KeyStoreException("Unsupported key algorithm: " + keyAlgorithm);
- }
- specBuilder.setUserAuthenticationRequired(false);
-
- return specBuilder.build();
- }
-
- private void setPrivateKeyEntry(String alias, PrivateKey key, Certificate[] chain,
- java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
- int flags = 0;
- KeyProtection spec;
- if (param == null) {
- spec = getLegacyKeyProtectionParameter(key);
- } else if (param instanceof KeyStoreParameter) {
- spec = getLegacyKeyProtectionParameter(key);
- KeyStoreParameter legacySpec = (KeyStoreParameter) param;
- if (legacySpec.isEncryptionRequired()) {
- flags = KeyStore.FLAG_ENCRYPTED;
- }
- } else if (param instanceof KeyProtection) {
- spec = (KeyProtection) param;
- if (spec.isCriticalToDeviceEncryption()) {
- flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
- }
-
- if (spec.isStrongBoxBacked()) {
- flags |= KeyStore.FLAG_STRONGBOX;
- }
- } else {
- throw new KeyStoreException(
- "Unsupported protection parameter class:" + param.getClass().getName()
- + ". Supported: " + KeyProtection.class.getName() + ", "
- + KeyStoreParameter.class.getName());
- }
-
- // Make sure the chain exists since this is a PrivateKey
- if ((chain == null) || (chain.length == 0)) {
- throw new KeyStoreException("Must supply at least one Certificate with PrivateKey");
- }
-
- // Do chain type checking.
- X509Certificate[] x509chain = new X509Certificate[chain.length];
- for (int i = 0; i < chain.length; i++) {
- if (!"X.509".equals(chain[i].getType())) {
- throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #"
- + i);
- }
-
- if (!(chain[i] instanceof X509Certificate)) {
- throw new KeyStoreException("Certificates must be in X.509 format: invalid cert #"
- + i);
- }
-
- x509chain[i] = (X509Certificate) chain[i];
- }
-
- final byte[] userCertBytes;
- try {
- userCertBytes = x509chain[0].getEncoded();
- } catch (CertificateEncodingException e) {
- throw new KeyStoreException("Failed to encode certificate #0", e);
- }
-
- /*
- * If we have a chain, store it in the CA certificate slot for this
- * alias as concatenated DER-encoded certificates. These can be
- * deserialized by {@link CertificateFactory#generateCertificates}.
- */
- final byte[] chainBytes;
- if (chain.length > 1) {
- /*
- * The chain is passed in as {user_cert, ca_cert_1, ca_cert_2, ...}
- * so we only need the certificates starting at index 1.
- */
- final byte[][] certsBytes = new byte[x509chain.length - 1][];
- int totalCertLength = 0;
- for (int i = 0; i < certsBytes.length; i++) {
- try {
- certsBytes[i] = x509chain[i + 1].getEncoded();
- totalCertLength += certsBytes[i].length;
- } catch (CertificateEncodingException e) {
- throw new KeyStoreException("Failed to encode certificate #" + i, e);
- }
- }
-
- /*
- * Serialize this into one byte array so we can later call
- * CertificateFactory#generateCertificates to recover them.
- */
- chainBytes = new byte[totalCertLength];
- int outputOffset = 0;
- for (int i = 0; i < certsBytes.length; i++) {
- final int certLength = certsBytes[i].length;
- System.arraycopy(certsBytes[i], 0, chainBytes, outputOffset, certLength);
- outputOffset += certLength;
- certsBytes[i] = null;
- }
- } else {
- chainBytes = null;
- }
-
- final String pkeyAlias;
- if (key instanceof AndroidKeyStorePrivateKey) {
- pkeyAlias = ((AndroidKeyStoreKey) key).getAlias();
- } else {
- pkeyAlias = null;
- }
-
- byte[] pkcs8EncodedPrivateKeyBytes;
- KeymasterArguments importArgs;
- final boolean shouldReplacePrivateKey;
- if (pkeyAlias != null && pkeyAlias.startsWith(Credentials.USER_PRIVATE_KEY)) {
- final String keySubalias = pkeyAlias.substring(Credentials.USER_PRIVATE_KEY.length());
- if (!alias.equals(keySubalias)) {
- throw new KeyStoreException("Can only replace keys with same alias: " + alias
- + " != " + keySubalias);
- }
- shouldReplacePrivateKey = false;
- importArgs = null;
- pkcs8EncodedPrivateKeyBytes = null;
- } else {
- shouldReplacePrivateKey = true;
- // Make sure the PrivateKey format is the one we support.
- final String keyFormat = key.getFormat();
- if ((keyFormat == null) || (!"PKCS#8".equals(keyFormat))) {
- throw new KeyStoreException(
- "Unsupported private key export format: " + keyFormat
- + ". Only private keys which export their key material in PKCS#8 format are"
- + " supported.");
- }
-
- // Make sure we can actually encode the key.
- pkcs8EncodedPrivateKeyBytes = key.getEncoded();
- if (pkcs8EncodedPrivateKeyBytes == null) {
- throw new KeyStoreException("Private key did not export any key material");
- }
-
- importArgs = new KeymasterArguments();
- try {
- importArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM,
- KeyProperties.KeyAlgorithm.toKeymasterAsymmetricKeyAlgorithm(
- key.getAlgorithm()));
- @KeyProperties.PurposeEnum int purposes = spec.getPurposes();
- importArgs.addEnums(KeymasterDefs.KM_TAG_PURPOSE,
- KeyProperties.Purpose.allToKeymaster(purposes));
- if (spec.isDigestsSpecified()) {
- importArgs.addEnums(KeymasterDefs.KM_TAG_DIGEST,
- KeyProperties.Digest.allToKeymaster(spec.getDigests()));
- }
-
- importArgs.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE,
- KeyProperties.BlockMode.allToKeymaster(spec.getBlockModes()));
- int[] keymasterEncryptionPaddings =
- KeyProperties.EncryptionPadding.allToKeymaster(
- spec.getEncryptionPaddings());
- if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (spec.isRandomizedEncryptionRequired())) {
- for (int keymasterPadding : keymasterEncryptionPaddings) {
- if (!KeymasterUtils
- .isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
- keymasterPadding)) {
- throw new KeyStoreException(
- "Randomized encryption (IND-CPA) required but is violated by"
- + " encryption padding mode: "
- + KeyProperties.EncryptionPadding.fromKeymaster(
- keymasterPadding)
- + ". See KeyProtection documentation.");
- }
- }
- }
- importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterEncryptionPaddings);
- importArgs.addEnums(KeymasterDefs.KM_TAG_PADDING,
- KeyProperties.SignaturePadding.allToKeymaster(spec.getSignaturePaddings()));
- KeymasterUtils.addUserAuthArgs(importArgs, spec);
- importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
- spec.getKeyValidityStart());
- importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- spec.getKeyValidityForOriginationEnd());
- importArgs.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- spec.getKeyValidityForConsumptionEnd());
- } catch (IllegalArgumentException | IllegalStateException e) {
- throw new KeyStoreException(e);
- }
- }
-
-
- boolean success = false;
- try {
- // Store the private key, if necessary
- if (shouldReplacePrivateKey) {
- // Delete the stored private key and any related entries before importing the
- // provided key
- Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
- KeyCharacteristics resultingKeyCharacteristics = new KeyCharacteristics();
- int errorCode = mKeyStore.importKey(
- Credentials.USER_PRIVATE_KEY + alias,
- importArgs,
- KeymasterDefs.KM_KEY_FORMAT_PKCS8,
- pkcs8EncodedPrivateKeyBytes,
- mUid,
- flags,
- resultingKeyCharacteristics);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new KeyStoreException("Failed to store private key",
- KeyStore.getKeyStoreException(errorCode));
- }
- } else {
- // Keep the stored private key around -- delete all other entry types
- Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
- Credentials.deleteLegacyKeyForAlias(mKeyStore, alias, mUid);
- }
-
- // Store the leaf certificate
- int errorCode = mKeyStore.insert(Credentials.USER_CERTIFICATE + alias, userCertBytes,
- mUid, flags);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new KeyStoreException("Failed to store certificate #0",
- KeyStore.getKeyStoreException(errorCode));
- }
-
- // Store the certificate chain
- errorCode = mKeyStore.insert(Credentials.CA_CERTIFICATE + alias, chainBytes,
- mUid, flags);
- if (errorCode != KeyStore.NO_ERROR) {
- throw new KeyStoreException("Failed to store certificate chain",
- KeyStore.getKeyStoreException(errorCode));
- }
- success = true;
- } finally {
- if (!success) {
- if (shouldReplacePrivateKey) {
- Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
- } else {
- Credentials.deleteCertificateTypesForAlias(mKeyStore, alias, mUid);
- Credentials.deleteLegacyKeyForAlias(mKeyStore, alias, mUid);
- }
- }
- }
- }
-
- private void setSecretKeyEntry(String entryAlias, SecretKey key,
- java.security.KeyStore.ProtectionParameter param)
- throws KeyStoreException {
- if ((param != null) && (!(param instanceof KeyProtection))) {
- throw new KeyStoreException(
- "Unsupported protection parameter class: " + param.getClass().getName()
- + ". Supported: " + KeyProtection.class.getName());
- }
- KeyProtection params = (KeyProtection) param;
-
- if (key instanceof AndroidKeyStoreSecretKey) {
- // KeyStore-backed secret key. It cannot be duplicated into another entry and cannot
- // overwrite its own entry.
- String keyAliasInKeystore = ((AndroidKeyStoreSecretKey) key).getAlias();
- if (keyAliasInKeystore == null) {
- throw new KeyStoreException("KeyStore-backed secret key does not have an alias");
- }
- String keyAliasPrefix = Credentials.USER_PRIVATE_KEY;
- if (!keyAliasInKeystore.startsWith(keyAliasPrefix)) {
- // try legacy prefix
- keyAliasPrefix = Credentials.USER_SECRET_KEY;
- if (!keyAliasInKeystore.startsWith(keyAliasPrefix)) {
- throw new KeyStoreException("KeyStore-backed secret key has invalid alias: "
- + keyAliasInKeystore);
- }
- }
- String keyEntryAlias =
- keyAliasInKeystore.substring(keyAliasPrefix.length());
- if (!entryAlias.equals(keyEntryAlias)) {
- throw new KeyStoreException("Can only replace KeyStore-backed keys with same"
- + " alias: " + entryAlias + " != " + keyEntryAlias);
- }
- // This is the entry where this key is already stored. No need to do anything.
- if (params != null) {
- throw new KeyStoreException("Modifying KeyStore-backed key using protection"
- + " parameters not supported");
- }
- return;
- }
-
- if (params == null) {
- throw new KeyStoreException(
- "Protection parameters must be specified when importing a symmetric key");
- }
-
- // Not a KeyStore-backed secret key -- import its key material into keystore.
- String keyExportFormat = key.getFormat();
- if (keyExportFormat == null) {
- throw new KeyStoreException(
- "Only secret keys that export their key material are supported");
- } else if (!"RAW".equals(keyExportFormat)) {
- throw new KeyStoreException(
- "Unsupported secret key material export format: " + keyExportFormat);
- }
- byte[] keyMaterial = key.getEncoded();
- if (keyMaterial == null) {
- throw new KeyStoreException("Key did not export its key material despite supporting"
- + " RAW format export");
- }
-
- KeymasterArguments args = new KeymasterArguments();
- try {
- int keymasterAlgorithm =
- KeyProperties.KeyAlgorithm.toKeymasterSecretKeyAlgorithm(key.getAlgorithm());
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, keymasterAlgorithm);
-
- int[] keymasterDigests;
- if (keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_HMAC) {
- // JCA HMAC key algorithm implies a digest (e.g., HmacSHA256 key algorithm
- // implies SHA-256 digest). Because keymaster HMAC key is authorized only for one
- // digest, we don't let import parameters override the digest implied by the key.
- // If the parameters specify digests at all, they must specify only one digest, the
- // only implied by key algorithm.
- int keymasterImpliedDigest =
- KeyProperties.KeyAlgorithm.toKeymasterDigest(key.getAlgorithm());
- if (keymasterImpliedDigest == -1) {
- throw new ProviderException(
- "HMAC key algorithm digest unknown for key algorithm "
- + key.getAlgorithm());
- }
- keymasterDigests = new int[] {keymasterImpliedDigest};
- if (params.isDigestsSpecified()) {
- // Digest(s) explicitly specified in params -- check that the list consists of
- // exactly one digest, the one implied by key algorithm.
- int[] keymasterDigestsFromParams =
- KeyProperties.Digest.allToKeymaster(params.getDigests());
- if ((keymasterDigestsFromParams.length != 1)
- || (keymasterDigestsFromParams[0] != keymasterImpliedDigest)) {
- throw new KeyStoreException(
- "Unsupported digests specification: "
- + Arrays.asList(params.getDigests()) + ". Only "
- + KeyProperties.Digest.fromKeymaster(keymasterImpliedDigest)
- + " supported for HMAC key algorithm " + key.getAlgorithm());
- }
- }
- } else {
- // Key algorithm does not imply a digest.
- if (params.isDigestsSpecified()) {
- keymasterDigests = KeyProperties.Digest.allToKeymaster(params.getDigests());
- } else {
- keymasterDigests = EmptyArray.INT;
- }
- }
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, keymasterDigests);
-
- @KeyProperties.PurposeEnum int purposes = params.getPurposes();
- int[] keymasterBlockModes =
- KeyProperties.BlockMode.allToKeymaster(params.getBlockModes());
- if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (params.isRandomizedEncryptionRequired())) {
- for (int keymasterBlockMode : keymasterBlockModes) {
- if (!KeymasterUtils.isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
- keymasterBlockMode)) {
- throw new KeyStoreException(
- "Randomized encryption (IND-CPA) required but may be violated by"
- + " block mode: "
- + KeyProperties.BlockMode.fromKeymaster(keymasterBlockMode)
- + ". See KeyProtection documentation.");
- }
- }
- }
- args.addEnums(KeymasterDefs.KM_TAG_PURPOSE,
- KeyProperties.Purpose.allToKeymaster(purposes));
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, keymasterBlockModes);
- if (params.getSignaturePaddings().length > 0) {
- throw new KeyStoreException("Signature paddings not supported for symmetric keys");
- }
- int[] keymasterPaddings = KeyProperties.EncryptionPadding.allToKeymaster(
- params.getEncryptionPaddings());
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, keymasterPaddings);
- KeymasterUtils.addUserAuthArgs(args, params);
- KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
- args,
- keymasterAlgorithm,
- keymasterBlockModes,
- keymasterDigests);
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
- params.getKeyValidityStart());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
- params.getKeyValidityForOriginationEnd());
- args.addDateIfNotNull(KeymasterDefs.KM_TAG_USAGE_EXPIRE_DATETIME,
- params.getKeyValidityForConsumptionEnd());
-
- if (((purposes & KeyProperties.PURPOSE_ENCRYPT) != 0)
- && (!params.isRandomizedEncryptionRequired())) {
- // Permit caller-provided IV when encrypting with this key
- args.addBoolean(KeymasterDefs.KM_TAG_CALLER_NONCE);
- }
- } catch (IllegalArgumentException | IllegalStateException e) {
- throw new KeyStoreException(e);
- }
- int flags = 0;
- if (params.isCriticalToDeviceEncryption()) {
- flags |= KeyStore.FLAG_CRITICAL_TO_DEVICE_ENCRYPTION;
- }
- if (params.isStrongBoxBacked()) {
- flags |= KeyStore.FLAG_STRONGBOX;
- }
-
- Credentials.deleteAllTypesForAlias(mKeyStore, entryAlias, mUid);
- String keyAliasInKeystore = Credentials.USER_PRIVATE_KEY + entryAlias;
- int errorCode = mKeyStore.importKey(
- keyAliasInKeystore,
- args,
- KeymasterDefs.KM_KEY_FORMAT_RAW,
- keyMaterial,
- mUid,
- flags,
- new KeyCharacteristics());
- if (errorCode != KeyStore.NO_ERROR) {
- throw new KeyStoreException("Failed to import secret key. Keystore error code: "
- + errorCode);
- }
- }
-
- private void setWrappedKeyEntry(String alias, WrappedKeyEntry entry,
- java.security.KeyStore.ProtectionParameter param) throws KeyStoreException {
- if (param != null) {
- throw new KeyStoreException("Protection parameters are specified inside wrapped keys");
- }
-
- byte[] maskingKey = new byte[32];
-
-
- KeymasterArguments args = new KeymasterArguments();
- String[] parts = entry.getTransformation().split("/");
-
- String algorithm = parts[0];
- if (KeyProperties.KEY_ALGORITHM_RSA.equalsIgnoreCase(algorithm)) {
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
- } else if (KeyProperties.KEY_ALGORITHM_EC.equalsIgnoreCase(algorithm)) {
- args.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_RSA);
- }
-
- if (parts.length > 1) {
- String mode = parts[1];
- if (KeyProperties.BLOCK_MODE_ECB.equalsIgnoreCase(mode)) {
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_ECB);
- } else if (KeyProperties.BLOCK_MODE_CBC.equalsIgnoreCase(mode)) {
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CBC);
- } else if (KeyProperties.BLOCK_MODE_CTR.equalsIgnoreCase(mode)) {
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_CTR);
- } else if (KeyProperties.BLOCK_MODE_GCM.equalsIgnoreCase(mode)) {
- args.addEnums(KeymasterDefs.KM_TAG_BLOCK_MODE, KeymasterDefs.KM_MODE_GCM);
- }
- }
-
- if (parts.length > 2) {
- String padding = parts[2];
- if (KeyProperties.ENCRYPTION_PADDING_NONE.equalsIgnoreCase(padding)) {
- // Noop
- } else if (KeyProperties.ENCRYPTION_PADDING_PKCS7.equalsIgnoreCase(padding)) {
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_PKCS7);
- } else if (KeyProperties.ENCRYPTION_PADDING_RSA_PKCS1.equalsIgnoreCase(padding)) {
- args.addEnums(KeymasterDefs.KM_TAG_PADDING,
- KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT);
- } else if (KeyProperties.ENCRYPTION_PADDING_RSA_OAEP.equalsIgnoreCase(padding)) {
- args.addEnums(KeymasterDefs.KM_TAG_PADDING, KeymasterDefs.KM_PAD_RSA_OAEP);
- }
- }
-
- KeyGenParameterSpec spec = (KeyGenParameterSpec) entry.getAlgorithmParameterSpec();
- if (spec.isDigestsSpecified()) {
- String digest = spec.getDigests()[0];
- if (KeyProperties.DIGEST_NONE.equalsIgnoreCase(digest)) {
- // Noop
- } else if (KeyProperties.DIGEST_MD5.equalsIgnoreCase(digest)) {
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_MD5);
- } else if (KeyProperties.DIGEST_SHA1.equalsIgnoreCase(digest)) {
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA1);
- } else if (KeyProperties.DIGEST_SHA224.equalsIgnoreCase(digest)) {
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_224);
- } else if (KeyProperties.DIGEST_SHA256.equalsIgnoreCase(digest)) {
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_256);
- } else if (KeyProperties.DIGEST_SHA384.equalsIgnoreCase(digest)) {
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_384);
- } else if (KeyProperties.DIGEST_SHA512.equalsIgnoreCase(digest)) {
- args.addEnums(KeymasterDefs.KM_TAG_DIGEST, KeymasterDefs.KM_DIGEST_SHA_2_512);
- }
- }
-
- int errorCode = mKeyStore.importWrappedKey(
- Credentials.USER_PRIVATE_KEY + alias,
- entry.getWrappedKeyBytes(),
- Credentials.USER_PRIVATE_KEY + entry.getWrappingKeyAlias(),
- maskingKey,
- args,
- GateKeeper.getSecureUserId(),
- 0, // FIXME fingerprint id?
- mUid,
- new KeyCharacteristics());
- if (errorCode == KeymasterDefs.KM_ERROR_UNIMPLEMENTED) {
- throw new SecureKeyImportUnavailableException("Could not import wrapped key");
- } else if (errorCode != KeyStore.NO_ERROR) {
- throw new KeyStoreException("Failed to import wrapped key. Keystore error code: "
- + errorCode);
- }
- }
-
- @Override
- public void engineSetKeyEntry(String alias, byte[] userKey, Certificate[] chain)
- throws KeyStoreException {
- throw new KeyStoreException("Operation not supported because key encoding is unknown");
- }
-
- @Override
- public void engineSetCertificateEntry(String alias, Certificate cert) throws KeyStoreException {
- if (isKeyEntry(alias)) {
- throw new KeyStoreException("Entry exists and is not a trusted certificate");
- }
-
- // We can't set something to null.
- if (cert == null) {
- throw new NullPointerException("cert == null");
- }
-
- final byte[] encoded;
- try {
- encoded = cert.getEncoded();
- } catch (CertificateEncodingException e) {
- throw new KeyStoreException(e);
- }
-
- if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, encoded, mUid, KeyStore.FLAG_NONE)) {
- throw new KeyStoreException("Couldn't insert certificate; is KeyStore initialized?");
- }
- }
-
- @Override
- public void engineDeleteEntry(String alias) throws KeyStoreException {
- if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid)) {
- throw new KeyStoreException("Failed to delete entry: " + alias);
- }
- }
-
- private Set<String> getUniqueAliases() {
- final String[] rawAliases = mKeyStore.list("", mUid);
- if (rawAliases == null) {
- return new HashSet<String>();
- }
-
- final Set<String> aliases = new HashSet<String>(rawAliases.length);
- for (String alias : rawAliases) {
- final int idx = alias.indexOf('_');
- if ((idx == -1) || (alias.length() <= idx)) {
- Log.e(NAME, "invalid alias: " + alias);
- continue;
- }
-
- aliases.add(new String(alias.substring(idx + 1)));
- }
-
- return aliases;
- }
-
- @Override
- public Enumeration<String> engineAliases() {
- return Collections.enumeration(getUniqueAliases());
- }
-
- @Override
- public boolean engineContainsAlias(String alias) {
- if (alias == null) {
- throw new NullPointerException("alias == null");
- }
-
- return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias, mUid)
- || mKeyStore.contains(Credentials.USER_SECRET_KEY + alias, mUid)
- || mKeyStore.contains(Credentials.USER_CERTIFICATE + alias, mUid)
- || mKeyStore.contains(Credentials.CA_CERTIFICATE + alias, mUid);
- }
-
- @Override
- public int engineSize() {
- return getUniqueAliases().size();
- }
-
- @Override
- public boolean engineIsKeyEntry(String alias) {
- return isKeyEntry(alias);
- }
-
- private boolean isKeyEntry(String alias) {
- return mKeyStore.contains(Credentials.USER_PRIVATE_KEY + alias, mUid) ||
- mKeyStore.contains(Credentials.USER_SECRET_KEY + alias, mUid);
- }
-
-
- private boolean isCertificateEntry(String alias) {
- if (alias == null) {
- throw new NullPointerException("alias == null");
- }
-
- return mKeyStore.contains(Credentials.CA_CERTIFICATE + alias, mUid);
- }
-
- @Override
- public boolean engineIsCertificateEntry(String alias) {
- return !isKeyEntry(alias) && isCertificateEntry(alias);
- }
-
- @Override
- public String engineGetCertificateAlias(Certificate cert) {
- if (cert == null) {
- return null;
- }
- if (!"X.509".equalsIgnoreCase(cert.getType())) {
- // Only X.509 certificates supported
- return null;
- }
- byte[] targetCertBytes;
- try {
- targetCertBytes = cert.getEncoded();
- } catch (CertificateEncodingException e) {
- return null;
- }
- if (targetCertBytes == null) {
- return null;
- }
-
- final Set<String> nonCaEntries = new HashSet<String>();
-
- /*
- * First scan the PrivateKeyEntry types. The KeyStoreSpi documentation
- * says to only compare the first certificate in the chain which is
- * equivalent to the USER_CERTIFICATE prefix for the Android keystore
- * convention.
- */
- final String[] certAliases = mKeyStore.list(Credentials.USER_CERTIFICATE, mUid);
- if (certAliases != null) {
- for (String alias : certAliases) {
- final byte[] certBytes = mKeyStore.get(Credentials.USER_CERTIFICATE + alias, mUid);
- if (certBytes == null) {
- continue;
- }
-
- nonCaEntries.add(alias);
-
- if (Arrays.equals(certBytes, targetCertBytes)) {
- return alias;
- }
- }
- }
-
- /*
- * Look at all the TrustedCertificateEntry types. Skip all the
- * PrivateKeyEntry we looked at above.
- */
- final String[] caAliases = mKeyStore.list(Credentials.CA_CERTIFICATE, mUid);
- if (certAliases != null) {
- for (String alias : caAliases) {
- if (nonCaEntries.contains(alias)) {
- continue;
- }
-
- final byte[] certBytes = mKeyStore.get(Credentials.CA_CERTIFICATE + alias, mUid);
- if (certBytes == null) {
- continue;
- }
-
- if (Arrays.equals(certBytes, targetCertBytes)) {
- return alias;
- }
- }
- }
-
- return null;
- }
-
- @Override
- public void engineStore(OutputStream stream, char[] password) throws IOException,
- NoSuchAlgorithmException, CertificateException {
- throw new UnsupportedOperationException("Can not serialize AndroidKeyStore to OutputStream");
- }
-
- @Override
- public void engineLoad(InputStream stream, char[] password) throws IOException,
- NoSuchAlgorithmException, CertificateException {
- if (stream != null) {
- throw new IllegalArgumentException("InputStream not supported");
- }
-
- if (password != null) {
- throw new IllegalArgumentException("password not supported");
- }
-
- // Unfortunate name collision.
- mKeyStore = KeyStore.getInstance();
- mUid = KeyStore.UID_SELF;
- }
-
- @Override
- public void engineLoad(LoadStoreParameter param) throws IOException,
- NoSuchAlgorithmException, CertificateException {
- int uid = KeyStore.UID_SELF;
- if (param != null) {
- if (param instanceof AndroidKeyStoreLoadStoreParameter) {
- uid = ((AndroidKeyStoreLoadStoreParameter) param).getUid();
- } else {
- throw new IllegalArgumentException(
- "Unsupported param type: " + param.getClass());
- }
- }
- mKeyStore = KeyStore.getInstance();
- mUid = uid;
- }
-
- @Override
- public void engineSetEntry(String alias, Entry entry, ProtectionParameter param)
- throws KeyStoreException {
- if (entry == null) {
- throw new KeyStoreException("entry == null");
- }
-
- Credentials.deleteAllTypesForAlias(mKeyStore, alias, mUid);
-
- if (entry instanceof java.security.KeyStore.TrustedCertificateEntry) {
- java.security.KeyStore.TrustedCertificateEntry trE =
- (java.security.KeyStore.TrustedCertificateEntry) entry;
- engineSetCertificateEntry(alias, trE.getTrustedCertificate());
- return;
- }
-
- if (entry instanceof PrivateKeyEntry) {
- PrivateKeyEntry prE = (PrivateKeyEntry) entry;
- setPrivateKeyEntry(alias, prE.getPrivateKey(), prE.getCertificateChain(), param);
- } else if (entry instanceof SecretKeyEntry) {
- SecretKeyEntry secE = (SecretKeyEntry) entry;
- setSecretKeyEntry(alias, secE.getSecretKey(), param);
- } else if (entry instanceof WrappedKeyEntry) {
- WrappedKeyEntry wke = (WrappedKeyEntry) entry;
- setWrappedKeyEntry(alias, wke, param);
- } else {
- throw new KeyStoreException(
- "Entry must be a PrivateKeyEntry, SecretKeyEntry or TrustedCertificateEntry"
- + "; was " + entry);
- }
- }
-
- /**
- * {@link X509Certificate} which returns {@link AndroidKeyStorePublicKey} from
- * {@link #getPublicKey()}. This is so that crypto operations on these public keys contain
- * can find out which keystore private key entry to use. This is needed so that Android Keystore
- * crypto operations using public keys can find out which key alias to use. These operations
- * require an alias.
- */
- static class KeyStoreX509Certificate extends DelegatingX509Certificate {
- private final String mPrivateKeyAlias;
- private final int mPrivateKeyUid;
- KeyStoreX509Certificate(String privateKeyAlias, int privateKeyUid,
- X509Certificate delegate) {
- super(delegate);
- mPrivateKeyAlias = privateKeyAlias;
- mPrivateKeyUid = privateKeyUid;
- }
-
- @Override
- public PublicKey getPublicKey() {
- PublicKey original = super.getPublicKey();
- return AndroidKeyStoreProvider.getAndroidKeyStorePublicKey(
- mPrivateKeyAlias, mPrivateKeyUid,
- original.getAlgorithm(), original.getEncoded());
- }
- }
-}
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
deleted file mode 100644
index 1f1d36f..0000000
--- a/keystore/java/android/security/keystore/AndroidKeyStoreUnauthenticatedAESCipherSpi.java
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.AlgorithmParameters;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.Key;
-import java.security.NoSuchAlgorithmException;
-import java.security.ProviderException;
-import java.security.spec.AlgorithmParameterSpec;
-import java.security.spec.InvalidParameterSpecException;
-import java.util.Arrays;
-
-import javax.crypto.CipherSpi;
-import javax.crypto.spec.IvParameterSpec;
-
-/**
- * Base class for Android Keystore unauthenticated AES {@link CipherSpi} implementations.
- *
- * @hide
- */
-class AndroidKeyStoreUnauthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
-
- abstract static class ECB extends AndroidKeyStoreUnauthenticatedAESCipherSpi {
- protected ECB(int keymasterPadding) {
- super(KeymasterDefs.KM_MODE_ECB, keymasterPadding, false);
- }
-
- public static class NoPadding extends ECB {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
- }
-
- public static class PKCS7Padding extends ECB {
- public PKCS7Padding() {
- super(KeymasterDefs.KM_PAD_PKCS7);
- }
- }
- }
-
- abstract static class CBC extends AndroidKeyStoreUnauthenticatedAESCipherSpi {
- protected CBC(int keymasterPadding) {
- super(KeymasterDefs.KM_MODE_CBC, keymasterPadding, true);
- }
-
- public static class NoPadding extends CBC {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
- }
-
- public static class PKCS7Padding extends CBC {
- public PKCS7Padding() {
- super(KeymasterDefs.KM_PAD_PKCS7);
- }
- }
- }
-
- abstract static class CTR extends AndroidKeyStoreUnauthenticatedAESCipherSpi {
- protected CTR(int keymasterPadding) {
- super(KeymasterDefs.KM_MODE_CTR, keymasterPadding, true);
- }
-
- public static class NoPadding extends CTR {
- public NoPadding() {
- super(KeymasterDefs.KM_PAD_NONE);
- }
- }
- }
-
- private static final int BLOCK_SIZE_BYTES = 16;
-
- private final int mKeymasterBlockMode;
- private final int mKeymasterPadding;
- /** Whether this transformation requires an IV. */
- private final boolean mIvRequired;
-
- private byte[] mIv;
-
- /** Whether the current {@code #mIv} has been used by the underlying crypto operation. */
- private boolean mIvHasBeenUsed;
-
- AndroidKeyStoreUnauthenticatedAESCipherSpi(
- int keymasterBlockMode,
- int keymasterPadding,
- boolean ivRequired) {
- mKeymasterBlockMode = keymasterBlockMode;
- mKeymasterPadding = keymasterPadding;
- mIvRequired = ivRequired;
- }
-
- @Override
- protected final void resetAll() {
- mIv = null;
- mIvHasBeenUsed = false;
- super.resetAll();
- }
-
- @Override
- protected final void resetWhilePreservingInitState() {
- super.resetWhilePreservingInitState();
- }
-
- @Override
- protected final void initKey(int opmode, Key key) throws InvalidKeyException {
- if (!(key instanceof AndroidKeyStoreSecretKey)) {
- throw new InvalidKeyException(
- "Unsupported key: " + ((key != null) ? key.getClass().getName() : "null"));
- }
- if (!KeyProperties.KEY_ALGORITHM_AES.equalsIgnoreCase(key.getAlgorithm())) {
- throw new InvalidKeyException(
- "Unsupported key algorithm: " + key.getAlgorithm() + ". Only " +
- KeyProperties.KEY_ALGORITHM_AES + " supported");
- }
- setKey((AndroidKeyStoreSecretKey) key);
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters() throws InvalidKeyException {
- if (!mIvRequired) {
- return;
- }
-
- // IV is used
- if (!isEncrypting()) {
- throw new InvalidKeyException("IV required when decrypting"
- + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
- }
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters(AlgorithmParameterSpec params)
- throws InvalidAlgorithmParameterException {
- if (!mIvRequired) {
- if (params != null) {
- throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
- }
- return;
- }
-
- // IV is used
- if (params == null) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException(
- "IvParameterSpec must be provided when decrypting");
- }
- return;
- }
- if (!(params instanceof IvParameterSpec)) {
- throw new InvalidAlgorithmParameterException("Only IvParameterSpec supported");
- }
- mIv = ((IvParameterSpec) params).getIV();
- if (mIv == null) {
- throw new InvalidAlgorithmParameterException("Null IV in IvParameterSpec");
- }
- }
-
- @Override
- protected final void initAlgorithmSpecificParameters(AlgorithmParameters params)
- throws InvalidAlgorithmParameterException {
- if (!mIvRequired) {
- if (params != null) {
- throw new InvalidAlgorithmParameterException("Unsupported parameters: " + params);
- }
- return;
- }
-
- // IV is used
- if (params == null) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException("IV required when decrypting"
- + ". Use IvParameterSpec or AlgorithmParameters to provide it.");
- }
- return;
- }
-
- if (!"AES".equalsIgnoreCase(params.getAlgorithm())) {
- throw new InvalidAlgorithmParameterException(
- "Unsupported AlgorithmParameters algorithm: " + params.getAlgorithm()
- + ". Supported: AES");
- }
-
- IvParameterSpec ivSpec;
- try {
- ivSpec = params.getParameterSpec(IvParameterSpec.class);
- } catch (InvalidParameterSpecException e) {
- if (!isEncrypting()) {
- // IV must be provided by the caller
- throw new InvalidAlgorithmParameterException("IV required when decrypting"
- + ", but not found in parameters: " + params, e);
- }
- mIv = null;
- return;
- }
- mIv = ivSpec.getIV();
- if (mIv == null) {
- throw new InvalidAlgorithmParameterException("Null IV in AlgorithmParameters");
- }
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForBegin() {
- if ((mIvRequired) && (mIv == null) && (isEncrypting())) {
- // IV will need to be generated
- return BLOCK_SIZE_BYTES;
- }
-
- return 0;
- }
-
- @Override
- protected final int getAdditionalEntropyAmountForFinish() {
- return 0;
- }
-
- @Override
- protected final void addAlgorithmSpecificParametersToBegin(
- @NonNull KeymasterArguments keymasterArgs) {
- if ((isEncrypting()) && (mIvRequired) && (mIvHasBeenUsed)) {
- // IV is being reused for encryption: this violates security best practices.
- throw new IllegalStateException(
- "IV has already been used. Reusing IV in encryption mode violates security best"
- + " practices.");
- }
-
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_ALGORITHM, KeymasterDefs.KM_ALGORITHM_AES);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_BLOCK_MODE, mKeymasterBlockMode);
- keymasterArgs.addEnum(KeymasterDefs.KM_TAG_PADDING, mKeymasterPadding);
- if ((mIvRequired) && (mIv != null)) {
- keymasterArgs.addBytes(KeymasterDefs.KM_TAG_NONCE, mIv);
- }
- }
-
- @Override
- protected final void loadAlgorithmSpecificParametersFromBeginResult(
- @NonNull KeymasterArguments keymasterArgs) {
- mIvHasBeenUsed = true;
-
- // NOTE: Keymaster doesn't always return an IV, even if it's used.
- byte[] returnedIv = keymasterArgs.getBytes(KeymasterDefs.KM_TAG_NONCE, null);
- if ((returnedIv != null) && (returnedIv.length == 0)) {
- returnedIv = null;
- }
-
- if (mIvRequired) {
- if (mIv == null) {
- mIv = returnedIv;
- } else if ((returnedIv != null) && (!Arrays.equals(returnedIv, mIv))) {
- throw new ProviderException("IV in use differs from provided IV");
- }
- } else {
- if (returnedIv != null) {
- throw new ProviderException(
- "IV in use despite IV not being used by this transformation");
- }
- }
- }
-
- @Override
- protected final int engineGetBlockSize() {
- return BLOCK_SIZE_BYTES;
- }
-
- @Override
- protected final int engineGetOutputSize(int inputLen) {
- return inputLen + 3 * BLOCK_SIZE_BYTES;
- }
-
- @Override
- protected final byte[] engineGetIV() {
- return ArrayUtils.cloneIfNotEmpty(mIv);
- }
-
- @Nullable
- @Override
- protected final AlgorithmParameters engineGetParameters() {
- if (!mIvRequired) {
- return null;
- }
- if ((mIv != null) && (mIv.length > 0)) {
- try {
- AlgorithmParameters params = AlgorithmParameters.getInstance("AES");
- params.init(new IvParameterSpec(mIv));
- return params;
- } catch (NoSuchAlgorithmException e) {
- throw new ProviderException(
- "Failed to obtain AES AlgorithmParameters", e);
- } catch (InvalidParameterSpecException e) {
- throw new ProviderException(
- "Failed to initialize AES AlgorithmParameters with an IV",
- e);
- }
- }
- return null;
- }
-}
diff --git a/keystore/java/android/security/keystore/KeyGenParameterSpec.java b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
index 9ca551b..1f9022b 100644
--- a/keystore/java/android/security/keystore/KeyGenParameterSpec.java
+++ b/keystore/java/android/security/keystore/KeyGenParameterSpec.java
@@ -446,13 +446,6 @@
@UnsupportedAppUsage
@Deprecated
public int getUid() {
- if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
- // If Keystore2 has not been enabled we have to behave as if mNamespace is actually
- // a UID, because we are still being used with the old Keystore SPI.
- // TODO This if statement and body can be removed when the Keystore 2 migration is
- // complete. b/171563717
- return mNamespace;
- }
try {
return KeyProperties.namespaceToLegacyUid(mNamespace);
} catch (IllegalArgumentException e) {
@@ -1021,14 +1014,6 @@
@NonNull
@Deprecated
public Builder setUid(int uid) {
- if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
- // If Keystore2 has not been enabled we have to behave as if mNamespace is actually
- // a UID, because we are still being used with the old Keystore SPI.
- // TODO This if statement and body can be removed when the Keystore 2 migration is
- // complete. b/171563717
- mNamespace = uid;
- return this;
- }
mNamespace = KeyProperties.legacyUidToNamespace(uid);
return this;
}
@@ -1666,9 +1651,10 @@
* Set whether this key is critical to the device encryption flow
*
* This is a special flag only available to system servers to indicate the current key
- * is part of the device encryption flow.
+ * is part of the device encryption flow. Setting this flag causes the key to not
+ * be cryptographically bound to the LSKF even if the key is otherwise authentication
+ * bound.
*
- * @see android.security.KeyStore#FLAG_CRITICAL_TO_DEVICE_ENCRYPTION
* @hide
*/
public Builder setCriticalToDeviceEncryption(boolean critical) {
diff --git a/keystore/java/android/security/keystore/KeyProtection.java b/keystore/java/android/security/keystore/KeyProtection.java
index fe92270..c14c3c5 100644
--- a/keystore/java/android/security/keystore/KeyProtection.java
+++ b/keystore/java/android/security/keystore/KeyProtection.java
@@ -24,6 +24,7 @@
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.security.GateKeeper;
+import android.security.keystore2.KeymasterUtils;
import java.security.Key;
import java.security.KeyStore.ProtectionParameter;
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
deleted file mode 100644
index 2c0f40d..0000000
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationChunkedStreamer.java
+++ /dev/null
@@ -1,225 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.os.IBinder;
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-import android.security.keymaster.KeymasterDefs;
-import android.security.keymaster.OperationResult;
-
-import libcore.util.EmptyArray;
-
-/**
- * Helper for streaming a crypto operation's input and output via {@link KeyStore} service's
- * {@code update} and {@code finish} operations.
- *
- * <p>The helper abstracts away issues that need to be solved in most code that uses KeyStore's
- * update and finish operations. Firstly, KeyStore's update operation can consume only a limited
- * amount of data in one go because the operations are marshalled via Binder. Secondly, the update
- * operation may consume less data than provided, in which case the caller has to buffer the
- * remainder for next time. Thirdly, when the input is smaller than a threshold, skipping update
- * and passing input data directly to final improves performance. This threshold is configurable;
- * using a threshold <= 1 causes the helper act eagerly, which may be required for some types of
- * operations (e.g. ciphers).
- *
- * <p>The helper exposes {@link #update(byte[], int, int) update} and
- * {@link #doFinal(byte[], int, int, byte[], byte[]) doFinal} operations which can be used to
- * conveniently implement various JCA crypto primitives.
- *
- * <p>Bidirectional chunked streaming of data via a KeyStore crypto operation is abstracted away as
- * a {@link Stream} to avoid having this class deal with operation tokens and occasional additional
- * parameters to {@code update} and {@code final} operations.
- *
- * @hide
- */
-class KeyStoreCryptoOperationChunkedStreamer implements KeyStoreCryptoOperationStreamer {
-
- /**
- * Bidirectional chunked data stream over a KeyStore crypto operation.
- */
- interface Stream {
- /**
- * Returns the result of the KeyStore {@code update} operation or null if keystore couldn't
- * be reached.
- */
- OperationResult update(byte[] input);
-
- /**
- * Returns the result of the KeyStore {@code finish} operation or null if keystore couldn't
- * be reached.
- */
- OperationResult finish(byte[] input, byte[] siganture, byte[] additionalEntropy);
- }
-
- // Binder buffer is about 1MB, but it's shared between all active transactions of the process.
- // Thus, it's safer to use a much smaller upper bound.
- private static final int DEFAULT_CHUNK_SIZE_MAX = 64 * 1024;
- // The chunk buffer will be sent to update until its size under this threshold.
- // This threshold should be <= the max input allowed for finish.
- // Setting this threshold <= 1 will effectivley disable buffering between updates.
- private static final int DEFAULT_CHUNK_SIZE_THRESHOLD = 2 * 1024;
-
- private final Stream mKeyStoreStream;
- private final int mChunkSizeMax;
- private final int mChunkSizeThreshold;
- private final byte[] mChunk;
- private int mChunkLength = 0;
- private long mConsumedInputSizeBytes;
- private long mProducedOutputSizeBytes;
-
- KeyStoreCryptoOperationChunkedStreamer(Stream operation) {
- this(operation, DEFAULT_CHUNK_SIZE_THRESHOLD, DEFAULT_CHUNK_SIZE_MAX);
- }
-
- KeyStoreCryptoOperationChunkedStreamer(Stream operation, int chunkSizeThreshold) {
- this(operation, chunkSizeThreshold, DEFAULT_CHUNK_SIZE_MAX);
- }
-
- KeyStoreCryptoOperationChunkedStreamer(Stream operation, int chunkSizeThreshold,
- int chunkSizeMax) {
- mKeyStoreStream = operation;
- mChunkSizeMax = chunkSizeMax;
- if (chunkSizeThreshold <= 0) {
- mChunkSizeThreshold = 1;
- } else if (chunkSizeThreshold > chunkSizeMax) {
- mChunkSizeThreshold = chunkSizeMax;
- } else {
- mChunkSizeThreshold = chunkSizeThreshold;
- }
- mChunk = new byte[mChunkSizeMax];
- }
-
- public byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException {
- if (inputLength == 0 || input == null) {
- // No input provided
- return EmptyArray.BYTE;
- }
- if (inputLength < 0 || inputOffset < 0 || (inputOffset + inputLength) > input.length) {
- throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
- "Input offset and length out of bounds of input array");
- }
-
- byte[] output = EmptyArray.BYTE;
-
- while (inputLength > 0 || mChunkLength >= mChunkSizeThreshold) {
- int inputConsumed = ArrayUtils.copy(input, inputOffset, mChunk, mChunkLength,
- inputLength);
- inputLength -= inputConsumed;
- inputOffset += inputConsumed;
- mChunkLength += inputConsumed;
- mConsumedInputSizeBytes += inputConsumed;
-
- if (mChunkLength > mChunkSizeMax) {
- throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH,
- "Chunk size exceeded max chunk size. Max: " + mChunkSizeMax
- + " Actual: " + mChunkLength);
- }
-
- if (mChunkLength >= mChunkSizeThreshold) {
- OperationResult opResult = mKeyStoreStream.update(
- ArrayUtils.subarray(mChunk, 0, mChunkLength));
-
- if (opResult == null) {
- throw new KeyStoreConnectException();
- } else if (opResult.resultCode != KeyStore.NO_ERROR) {
- throw KeyStore.getKeyStoreException(opResult.resultCode);
- }
- if (opResult.inputConsumed <= 0) {
- throw new KeyStoreException(KeymasterDefs.KM_ERROR_INVALID_INPUT_LENGTH,
- "Keystore consumed 0 of " + mChunkLength + " bytes provided.");
- } else if (opResult.inputConsumed > mChunkLength) {
- throw new KeyStoreException(KeymasterDefs.KM_ERROR_UNKNOWN_ERROR,
- "Keystore consumed more input than provided. Provided: "
- + mChunkLength + ", consumed: " + opResult.inputConsumed);
- }
- mChunkLength -= opResult.inputConsumed;
-
- if (mChunkLength > 0) {
- // Partialy consumed, shift chunk contents
- ArrayUtils.copy(mChunk, opResult.inputConsumed, mChunk, 0, mChunkLength);
- }
-
- if ((opResult.output != null) && (opResult.output.length > 0)) {
- // Output was produced
- mProducedOutputSizeBytes += opResult.output.length;
- output = ArrayUtils.concat(output, opResult.output);
- }
- }
- }
- return output;
- }
-
- public byte[] doFinal(byte[] input, int inputOffset, int inputLength,
- byte[] signature, byte[] additionalEntropy) throws KeyStoreException {
- byte[] output = update(input, inputOffset, inputLength);
- byte[] finalChunk = ArrayUtils.subarray(mChunk, 0, mChunkLength);
- OperationResult opResult = mKeyStoreStream.finish(finalChunk, signature, additionalEntropy);
-
- if (opResult == null) {
- throw new KeyStoreConnectException();
- } else if (opResult.resultCode != KeyStore.NO_ERROR) {
- throw KeyStore.getKeyStoreException(opResult.resultCode);
- }
- // If no error, assume all input consumed
- mConsumedInputSizeBytes += finalChunk.length;
-
- if ((opResult.output != null) && (opResult.output.length > 0)) {
- mProducedOutputSizeBytes += opResult.output.length;
- output = ArrayUtils.concat(output, opResult.output);
- }
-
- return output;
- }
-
- @Override
- public long getConsumedInputSizeBytes() {
- return mConsumedInputSizeBytes;
- }
-
- @Override
- public long getProducedOutputSizeBytes() {
- return mProducedOutputSizeBytes;
- }
-
- /**
- * Main data stream via a KeyStore streaming operation.
- *
- * <p>For example, for an encryption operation, this is the stream through which plaintext is
- * provided and ciphertext is obtained.
- */
- public static class MainDataStream implements Stream {
-
- private final KeyStore mKeyStore;
- private final IBinder mOperationToken;
-
- public MainDataStream(KeyStore keyStore, IBinder operationToken) {
- mKeyStore = keyStore;
- mOperationToken = operationToken;
- }
-
- @Override
- public OperationResult update(byte[] input) {
- return mKeyStore.update(mOperationToken, null, input);
- }
-
- @Override
- public OperationResult finish(byte[] input, byte[] signature, byte[] additionalEntropy) {
- return mKeyStore.finish(mOperationToken, null, input, signature, additionalEntropy);
- }
- }
-}
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java
deleted file mode 100644
index 062c2d4..0000000
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationStreamer.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.security.KeyStore;
-import android.security.KeyStoreException;
-
-/**
- * Helper for streaming a crypto operation's input and output via {@link KeyStore} service's
- * {@code update} and {@code finish} operations.
- *
- * <p>The helper abstracts away to issues that need to be solved in most code that uses KeyStore's
- * update and finish operations. Firstly, KeyStore's update operation can consume only a limited
- * amount of data in one go because the operations are marshalled via Binder. Secondly, the update
- * operation may consume less data than provided, in which case the caller has to buffer the
- * remainder for next time. The helper exposes {@link #update(byte[], int, int) update} and
- * {@link #doFinal(byte[], int, int, byte[], byte[]) doFinal} operations which can be used to
- * conveniently implement various JCA crypto primitives.
- *
- * @hide
- */
-interface KeyStoreCryptoOperationStreamer {
- byte[] update(byte[] input, int inputOffset, int inputLength) throws KeyStoreException;
- byte[] doFinal(byte[] input, int inputOffset, int inputLength, byte[] signature,
- byte[] additionalEntropy) throws KeyStoreException;
- long getConsumedInputSizeBytes();
- long getProducedOutputSizeBytes();
-}
diff --git a/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java b/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java
deleted file mode 100644
index c82b6e6b..0000000
--- a/keystore/java/android/security/keystore/KeyStoreCryptoOperationUtils.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.security.KeyStore;
-import android.security.keymaster.KeymasterDefs;
-
-import libcore.util.EmptyArray;
-
-import java.security.GeneralSecurityException;
-import java.security.InvalidAlgorithmParameterException;
-import java.security.InvalidKeyException;
-import java.security.SecureRandom;
-
-/**
- * Assorted utility methods for implementing crypto operations on top of KeyStore.
- *
- * @hide
- */
-abstract class KeyStoreCryptoOperationUtils {
-
- private static volatile SecureRandom sRng;
-
- private KeyStoreCryptoOperationUtils() {}
-
- /**
- * Returns the {@link InvalidKeyException} to be thrown by the {@code init} method of
- * the crypto operation in response to {@code KeyStore.begin} operation or {@code null} if
- * the {@code init} method should succeed.
- */
- static InvalidKeyException getInvalidKeyExceptionForInit(
- KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode) {
- if (beginOpResultCode == KeyStore.NO_ERROR) {
- return null;
- }
-
- // An error occurred. However, some errors should not lead to init throwing an exception.
- // See below.
- InvalidKeyException e =
- keyStore.getInvalidKeyException(key.getAlias(), key.getUid(), beginOpResultCode);
- switch (beginOpResultCode) {
- case KeyStore.OP_AUTH_NEEDED:
- // Operation needs to be authorized by authenticating the user. Don't throw an
- // exception is such authentication is possible for this key
- // (UserNotAuthenticatedException). An example of when it's not possible is where
- // the key is permanently invalidated (KeyPermanentlyInvalidatedException).
- if (e instanceof UserNotAuthenticatedException) {
- return null;
- }
- break;
- }
- return e;
- }
-
- /**
- * Returns the exception to be thrown by the {@code Cipher.init} method of the crypto operation
- * in response to {@code KeyStore.begin} operation or {@code null} if the {@code init} method
- * should succeed.
- */
- public static GeneralSecurityException getExceptionForCipherInit(
- KeyStore keyStore, AndroidKeyStoreKey key, int beginOpResultCode) {
- if (beginOpResultCode == KeyStore.NO_ERROR) {
- return null;
- }
-
- // Cipher-specific cases
- switch (beginOpResultCode) {
- case KeymasterDefs.KM_ERROR_INVALID_NONCE:
- return new InvalidAlgorithmParameterException("Invalid IV");
- case KeymasterDefs.KM_ERROR_CALLER_NONCE_PROHIBITED:
- return new InvalidAlgorithmParameterException("Caller-provided IV not permitted");
- }
-
- // General cases
- return getInvalidKeyExceptionForInit(keyStore, key, beginOpResultCode);
- }
-
- /**
- * Returns the requested number of random bytes to mix into keystore/keymaster RNG.
- *
- * @param rng RNG from which to obtain the random bytes or {@code null} for the platform-default
- * RNG.
- */
- static byte[] getRandomBytesToMixIntoKeystoreRng(SecureRandom rng, int sizeBytes) {
- if (sizeBytes <= 0) {
- return EmptyArray.BYTE;
- }
- if (rng == null) {
- rng = getRng();
- }
- byte[] result = new byte[sizeBytes];
- rng.nextBytes(result);
- return result;
- }
-
- private static SecureRandom getRng() {
- // IMPLEMENTATION NOTE: It's OK to share a SecureRandom instance because SecureRandom is
- // required to be thread-safe.
- if (sRng == null) {
- sRng = new SecureRandom();
- }
- return sRng;
- }
-}
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
deleted file mode 100644
index 670ef5e..0000000
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- * Copyright (C) 2015 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.keystore;
-
-import android.hardware.biometrics.BiometricManager;
-import android.security.GateKeeper;
-import android.security.KeyStore;
-import android.security.keymaster.KeymasterArguments;
-import android.security.keymaster.KeymasterDefs;
-
-import java.security.ProviderException;
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * @hide
- */
-public abstract class KeymasterUtils {
-
- private KeymasterUtils() {}
-
- public static int getDigestOutputSizeBits(int keymasterDigest) {
- switch (keymasterDigest) {
- case KeymasterDefs.KM_DIGEST_NONE:
- return -1;
- case KeymasterDefs.KM_DIGEST_MD5:
- return 128;
- case KeymasterDefs.KM_DIGEST_SHA1:
- return 160;
- case KeymasterDefs.KM_DIGEST_SHA_2_224:
- return 224;
- case KeymasterDefs.KM_DIGEST_SHA_2_256:
- return 256;
- case KeymasterDefs.KM_DIGEST_SHA_2_384:
- return 384;
- case KeymasterDefs.KM_DIGEST_SHA_2_512:
- return 512;
- default:
- throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
- }
- }
-
- public static boolean isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
- int keymasterBlockMode) {
- switch (keymasterBlockMode) {
- case KeymasterDefs.KM_MODE_ECB:
- return false;
- case KeymasterDefs.KM_MODE_CBC:
- case KeymasterDefs.KM_MODE_CTR:
- case KeymasterDefs.KM_MODE_GCM:
- return true;
- default:
- throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
- }
- }
-
- public static boolean isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
- int keymasterPadding) {
- switch (keymasterPadding) {
- case KeymasterDefs.KM_PAD_NONE:
- return false;
- case KeymasterDefs.KM_PAD_RSA_OAEP:
- case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
- return true;
- default:
- throw new IllegalArgumentException(
- "Unsupported asymmetric encryption padding scheme: " + keymasterPadding);
- }
- }
-
- private static void addSids(KeymasterArguments args, UserAuthArgs spec) {
- // If both biometric and credential are accepted, then just use the root sid from gatekeeper
- if (spec.getUserAuthenticationType() == (KeyProperties.AUTH_BIOMETRIC_STRONG
- | KeyProperties.AUTH_DEVICE_CREDENTIAL)) {
- if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
- args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
- KeymasterArguments.toUint64(spec.getBoundToSpecificSecureUserId()));
- } else {
- // The key is authorized for use for the specified amount of time after the user has
- // authenticated. Whatever unlocks the secure lock screen should authorize this key.
- args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
- KeymasterArguments.toUint64(getRootSid()));
- }
- } else {
- List<Long> sids = new ArrayList<>();
- if ((spec.getUserAuthenticationType() & KeyProperties.AUTH_BIOMETRIC_STRONG) != 0) {
- final BiometricManager bm = KeyStore.getApplicationContext()
- .getSystemService(BiometricManager.class);
-
- // TODO: Restore permission check in getAuthenticatorIds once the ID is no longer
- // needed here.
-
- final long[] biometricSids = bm.getAuthenticatorIds();
-
- if (biometricSids.length == 0) {
- throw new IllegalStateException(
- "At least one biometric must be enrolled to create keys requiring user"
- + " authentication for every use");
- }
-
- if (spec.getBoundToSpecificSecureUserId() != GateKeeper.INVALID_SECURE_USER_ID) {
- sids.add(spec.getBoundToSpecificSecureUserId());
- } else if (spec.isInvalidatedByBiometricEnrollment()) {
- // The biometric-only SIDs will change on biometric enrollment or removal of all
- // enrolled templates, invalidating the key.
- for (long sid : biometricSids) {
- sids.add(sid);
- }
- } else {
- // The root SID will *not* change on fingerprint enrollment, or removal of all
- // enrolled fingerprints, allowing the key to remain valid.
- sids.add(getRootSid());
- }
- } else if ((spec.getUserAuthenticationType() & KeyProperties.AUTH_DEVICE_CREDENTIAL)
- != 0) {
- sids.add(getRootSid());
- } else {
- throw new IllegalStateException("Invalid or no authentication type specified.");
- }
-
- for (int i = 0; i < sids.size(); i++) {
- args.addUnsignedLong(KeymasterDefs.KM_TAG_USER_SECURE_ID,
- KeymasterArguments.toUint64(sids.get(i)));
- }
- }
- }
-
- /**
- * Adds keymaster arguments to express the key's authorization policy supported by user
- * authentication.
- *
- * @param args The arguments sent to keymaster that need to be populated from the spec
- * @param spec The user authentication relevant portions of the spec passed in from the caller.
- * This spec will be translated into the relevant keymaster tags to be loaded into args.
- * @throws IllegalStateException if user authentication is required but the system is in a wrong
- * state (e.g., secure lock screen not set up) for generating or importing keys that
- * require user authentication.
- */
- public static void addUserAuthArgs(KeymasterArguments args, UserAuthArgs spec) {
-
- if (spec.isUserConfirmationRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_CONFIRMATION_REQUIRED);
- }
-
- if (spec.isUserPresenceRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_TRUSTED_USER_PRESENCE_REQUIRED);
- }
-
- if (spec.isUnlockedDeviceRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_UNLOCKED_DEVICE_REQUIRED);
- }
-
- if (!spec.isUserAuthenticationRequired()) {
- args.addBoolean(KeymasterDefs.KM_TAG_NO_AUTH_REQUIRED);
- return;
- }
-
- if (spec.getUserAuthenticationValidityDurationSeconds() == 0) {
- // Every use of this key needs to be authorized by the user.
- addSids(args, spec);
- args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, spec.getUserAuthenticationType());
-
- if (spec.isUserAuthenticationValidWhileOnBody()) {
- throw new ProviderException("Key validity extension while device is on-body is not "
- + "supported for keys requiring fingerprint authentication");
- }
- } else {
- addSids(args, spec);
- args.addEnum(KeymasterDefs.KM_TAG_USER_AUTH_TYPE, spec.getUserAuthenticationType());
- args.addUnsignedInt(KeymasterDefs.KM_TAG_AUTH_TIMEOUT,
- spec.getUserAuthenticationValidityDurationSeconds());
- if (spec.isUserAuthenticationValidWhileOnBody()) {
- args.addBoolean(KeymasterDefs.KM_TAG_ALLOW_WHILE_ON_BODY);
- }
- }
- }
-
- /**
- * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for
- * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC,
- * AES-GCM).
- */
- public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args,
- int keymasterAlgorithm,
- int[] keymasterBlockModes,
- int[] keymasterDigests) {
- switch (keymasterAlgorithm) {
- case KeymasterDefs.KM_ALGORITHM_AES:
- if (com.android.internal.util.ArrayUtils.contains(
- keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) {
- // AES GCM key needs the minimum length of AEAD tag specified.
- args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
- AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
- .MIN_SUPPORTED_TAG_LENGTH_BITS);
- }
- break;
- case KeymasterDefs.KM_ALGORITHM_HMAC:
- // HMAC key needs the minimum length of MAC set to the output size of the associated
- // digest. This is because we do not offer a way to generate shorter MACs and
- // don't offer a way to verify MACs (other than by generating them).
- if (keymasterDigests.length != 1) {
- throw new ProviderException(
- "Unsupported number of authorized digests for HMAC key: "
- + keymasterDigests.length
- + ". Exactly one digest must be authorized");
- }
- int keymasterDigest = keymasterDigests[0];
- int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest);
- if (digestOutputSizeBits == -1) {
- throw new ProviderException(
- "HMAC key authorized for unsupported digest: "
- + KeyProperties.Digest.fromKeymaster(keymasterDigest));
- }
- args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits);
- break;
- }
- }
-
- private static long getRootSid() {
- long rootSid = GateKeeper.getSecureUserId();
- if (rootSid == 0) {
- throw new IllegalStateException("Secure lock screen must be enabled"
- + " to create keys requiring user authentication");
- }
- return rootSid;
- }
-}
diff --git a/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java b/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
index d1cc572..c1842b4 100644
--- a/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
+++ b/keystore/java/android/security/keystore/SecureKeyImportUnavailableException.java
@@ -16,8 +16,8 @@
package android.security.keystore;
-import android.security.KeyStore;
import android.security.KeyStoreException;
+import android.security.keymaster.KeymasterDefs;
import java.security.ProviderException;
@@ -31,7 +31,7 @@
}
public SecureKeyImportUnavailableException(String message) {
- super(message, new KeyStoreException(KeyStore.HARDWARE_TYPE_UNAVAILABLE,
+ super(message, new KeyStoreException(KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE,
"Secure Key Import not available"));
}
diff --git a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
index 6c7e9a9..1f4e12e 100644
--- a/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
+++ b/keystore/java/android/security/keystore/StrongBoxUnavailableException.java
@@ -16,8 +16,8 @@
package android.security.keystore;
-import android.security.KeyStore;
import android.security.KeyStoreException;
+import android.security.keymaster.KeymasterDefs;
import java.security.ProviderException;
@@ -33,7 +33,8 @@
public StrongBoxUnavailableException(String message) {
super(message,
- new KeyStoreException(KeyStore.HARDWARE_TYPE_UNAVAILABLE, "No StrongBox available")
+ new KeyStoreException(KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE,
+ "No StrongBox available")
);
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
index 0f77749..268b15bf 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreHmacSpi.java
@@ -21,7 +21,6 @@
import android.security.KeyStoreOperation;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyStoreCryptoOperation;
-import android.security.keystore.KeymasterUtils;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
index 1575bb4..f1681ec 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyGeneratorSpi.java
@@ -20,12 +20,10 @@
import android.hardware.security.keymint.SecurityLevel;
import android.security.KeyStore2;
import android.security.KeyStoreSecurityLevel;
-import android.security.keymaster.KeymasterArguments;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.ArrayUtils;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
-import android.security.keystore.KeymasterUtils;
import android.security.keystore.StrongBoxUnavailableException;
import android.system.keystore2.Domain;
import android.system.keystore2.IKeystoreSecurityLevel;
@@ -259,7 +257,7 @@
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), spec);
+ KeyStore2ParameterUtils.addUserAuthArgs(new ArrayList<>(), spec);
} catch (IllegalStateException | IllegalArgumentException e) {
throw new InvalidAlgorithmParameterException(e);
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
index 2d8901a..c26d9f583 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreKeyPairGeneratorSpi.java
@@ -18,6 +18,7 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.app.ActivityThread;
import android.content.Context;
import android.hardware.security.keymint.KeyParameter;
import android.hardware.security.keymint.KeyPurpose;
@@ -28,7 +29,6 @@
import android.security.GenerateRkpKey;
import android.security.GenerateRkpKeyException;
import android.security.KeyPairGeneratorSpec;
-import android.security.KeyStore;
import android.security.KeyStore2;
import android.security.KeyStoreException;
import android.security.KeyStoreSecurityLevel;
@@ -39,7 +39,6 @@
import android.security.keystore.DeviceIdAttestationException;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
-import android.security.keystore.KeymasterUtils;
import android.security.keystore.SecureKeyImportUnavailableException;
import android.security.keystore.StrongBoxUnavailableException;
import android.system.keystore2.Authorization;
@@ -270,7 +269,7 @@
// Check that user authentication related parameters are acceptable. This method
// will throw an IllegalStateException if there are issues (e.g., secure lock screen
// not set up).
- KeymasterUtils.addUserAuthArgs(new KeymasterArguments(), mSpec);
+ KeyStore2ParameterUtils.addUserAuthArgs(new ArrayList<>(), mSpec);
} catch (IllegalArgumentException | IllegalStateException e) {
throw new InvalidAlgorithmParameterException(e);
}
@@ -572,7 +571,8 @@
AndroidKeyStorePublicKey publicKey =
AndroidKeyStoreProvider.makeAndroidKeyStorePublicKeyFromKeyEntryResponse(
descriptor, metadata, iSecurityLevel, mKeymasterAlgorithm);
- GenerateRkpKey keyGen = new GenerateRkpKey(KeyStore.getApplicationContext());
+ GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread
+ .currentApplication());
try {
if (mSpec.getAttestationChallenge() != null) {
keyGen.notifyKeyGenerated(securityLevel);
@@ -589,7 +589,8 @@
case KeymasterDefs.KM_ERROR_HARDWARE_TYPE_UNAVAILABLE:
throw new StrongBoxUnavailableException("Failed to generated key pair.", e);
case ResponseCode.OUT_OF_KEYS:
- GenerateRkpKey keyGen = new GenerateRkpKey(KeyStore.getApplicationContext());
+ GenerateRkpKey keyGen = new GenerateRkpKey(ActivityThread
+ .currentApplication());
try {
keyGen.notifyEmpty(securityLevel);
} catch (RemoteException f) {
@@ -665,8 +666,8 @@
if (idTypesSet.contains(AttestationUtils.ID_TYPE_IMEI)
|| idTypesSet.contains(AttestationUtils.ID_TYPE_MEID)) {
telephonyService =
- (TelephonyManager) KeyStore.getApplicationContext().getSystemService(
- Context.TELEPHONY_SERVICE);
+ (TelephonyManager) android.app.AppGlobals.getInitialApplication()
+ .getSystemService(Context.TELEPHONY_SERVICE);
if (telephonyService == null) {
throw new DeviceIdAttestationException("Unable to access telephony service");
}
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
index ba6d22f..89d2b74 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreProvider.java
@@ -110,23 +110,6 @@
putSecretKeyFactoryImpl("HmacSHA512");
}
- private static boolean sInstalled = false;
-
- /**
- * This function indicates whether or not this provider was installed. This is manly used
- * as indicator for
- * {@link android.security.keystore.AndroidKeyStoreProvider#getKeyStoreForUid(int)}
- * to whether or not to retrieve the Keystore provider by "AndroidKeyStoreLegacy".
- * This function can be removed once the transition to Keystore 2.0 is complete.
- * b/171305684
- *
- * @return true if this provider was installed.
- * @hide
- */
- public static boolean isInstalled() {
- return sInstalled;
- }
-
/**
* Installs a new instance of this provider (and the
* {@link AndroidKeyStoreBCWorkaroundProvider}).
@@ -142,7 +125,6 @@
break;
}
}
- sInstalled = true;
Security.addProvider(new AndroidKeyStoreProvider());
Provider workaroundProvider = new AndroidKeyStoreBCWorkaroundProvider();
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
index 6ff9432..5848247 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreRSACipherSpi.java
@@ -21,7 +21,6 @@
import android.hardware.security.keymint.KeyParameter;
import android.security.keymaster.KeymasterDefs;
import android.security.keystore.KeyProperties;
-import android.security.keystore.KeymasterUtils;
import android.system.keystore2.Authorization;
import java.security.AlgorithmParameters;
diff --git a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
index 32f98a2..3e2fb94 100644
--- a/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore2/AndroidKeyStoreSpi.java
@@ -30,7 +30,6 @@
import android.security.keystore.KeyPermanentlyInvalidatedException;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
-import android.security.keystore.KeymasterUtils;
import android.security.keystore.SecureKeyImportUnavailableException;
import android.security.keystore.WrappedKeyEntry;
import android.system.keystore2.AuthenticatorSpec;
diff --git a/keystore/java/android/security/keystore2/KeymasterUtils.java b/keystore/java/android/security/keystore2/KeymasterUtils.java
new file mode 100644
index 0000000..de4696c
--- /dev/null
+++ b/keystore/java/android/security/keystore2/KeymasterUtils.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2021 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.keystore2;
+
+import android.security.keymaster.KeymasterArguments;
+import android.security.keymaster.KeymasterDefs;
+import android.security.keystore.KeyProperties;
+
+import java.security.ProviderException;
+
+/**
+ * @hide
+ */
+public abstract class KeymasterUtils {
+
+ private KeymasterUtils() {}
+
+ /** @hide */
+ static int getDigestOutputSizeBits(int keymasterDigest) {
+ switch (keymasterDigest) {
+ case KeymasterDefs.KM_DIGEST_NONE:
+ return -1;
+ case KeymasterDefs.KM_DIGEST_MD5:
+ return 128;
+ case KeymasterDefs.KM_DIGEST_SHA1:
+ return 160;
+ case KeymasterDefs.KM_DIGEST_SHA_2_224:
+ return 224;
+ case KeymasterDefs.KM_DIGEST_SHA_2_256:
+ return 256;
+ case KeymasterDefs.KM_DIGEST_SHA_2_384:
+ return 384;
+ case KeymasterDefs.KM_DIGEST_SHA_2_512:
+ return 512;
+ default:
+ throw new IllegalArgumentException("Unknown digest: " + keymasterDigest);
+ }
+ }
+
+ /** @hide */
+ static boolean isKeymasterBlockModeIndCpaCompatibleWithSymmetricCrypto(
+ int keymasterBlockMode) {
+ switch (keymasterBlockMode) {
+ case KeymasterDefs.KM_MODE_ECB:
+ return false;
+ case KeymasterDefs.KM_MODE_CBC:
+ case KeymasterDefs.KM_MODE_CTR:
+ case KeymasterDefs.KM_MODE_GCM:
+ return true;
+ default:
+ throw new IllegalArgumentException("Unsupported block mode: " + keymasterBlockMode);
+ }
+ }
+
+ /** @hide */
+ static boolean isKeymasterPaddingSchemeIndCpaCompatibleWithAsymmetricCrypto(
+ int keymasterPadding) {
+ switch (keymasterPadding) {
+ case KeymasterDefs.KM_PAD_NONE:
+ return false;
+ case KeymasterDefs.KM_PAD_RSA_OAEP:
+ case KeymasterDefs.KM_PAD_RSA_PKCS1_1_5_ENCRYPT:
+ return true;
+ default:
+ throw new IllegalArgumentException(
+ "Unsupported asymmetric encryption padding scheme: " + keymasterPadding);
+ }
+ }
+
+ /**
+ * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for
+ * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC,
+ * AES-GCM).
+ */
+ public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args,
+ int keymasterAlgorithm,
+ int[] keymasterBlockModes,
+ int[] keymasterDigests) {
+ switch (keymasterAlgorithm) {
+ case KeymasterDefs.KM_ALGORITHM_AES:
+ if (com.android.internal.util.ArrayUtils.contains(
+ keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) {
+ // AES GCM key needs the minimum length of AEAD tag specified.
+ args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
+ AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
+ .MIN_SUPPORTED_TAG_LENGTH_BITS);
+ }
+ break;
+ case KeymasterDefs.KM_ALGORITHM_HMAC:
+ // HMAC key needs the minimum length of MAC set to the output size of the associated
+ // digest. This is because we do not offer a way to generate shorter MACs and
+ // don't offer a way to verify MACs (other than by generating them).
+ if (keymasterDigests.length != 1) {
+ throw new ProviderException(
+ "Unsupported number of authorized digests for HMAC key: "
+ + keymasterDigests.length
+ + ". Exactly one digest must be authorized");
+ }
+ int keymasterDigest = keymasterDigests[0];
+ int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest);
+ if (digestOutputSizeBits == -1) {
+ throw new ProviderException(
+ "HMAC key authorized for unsupported digest: "
+ + KeyProperties.Digest.fromKeymaster(keymasterDigest));
+ }
+ args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits);
+ break;
+ }
+ }
+}
diff --git a/packages/Connectivity/framework/api/current.txt b/packages/Connectivity/framework/api/current.txt
index 7428c6e..9c77c85 100644
--- a/packages/Connectivity/framework/api/current.txt
+++ b/packages/Connectivity/framework/api/current.txt
@@ -298,7 +298,6 @@
method @Nullable public android.net.NetworkSpecifier getNetworkSpecifier();
method public int getOwnerUid();
method public int getSignalStrength();
- method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
method @Nullable public android.net.TransportInfo getTransportInfo();
method public boolean hasCapability(int);
method public boolean hasTransport(int);
@@ -410,7 +409,6 @@
method public android.net.NetworkRequest.Builder removeTransportType(int);
method @Deprecated public android.net.NetworkRequest.Builder setNetworkSpecifier(String);
method public android.net.NetworkRequest.Builder setNetworkSpecifier(android.net.NetworkSpecifier);
- method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
}
public class ParseException extends java.lang.RuntimeException {
diff --git a/packages/Connectivity/framework/api/system-current.txt b/packages/Connectivity/framework/api/system-current.txt
index 5613ca1..847bcbc 100644
--- a/packages/Connectivity/framework/api/system-current.txt
+++ b/packages/Connectivity/framework/api/system-current.txt
@@ -276,6 +276,7 @@
method @NonNull public int[] getAdministratorUids();
method @Nullable public static String getCapabilityCarrierName(int);
method @Nullable public String getSsid();
+ method @NonNull public java.util.Set<java.lang.Integer> getSubIds();
method @NonNull public int[] getTransportTypes();
method public boolean isPrivateDnsBroken();
method public boolean satisfiedByNetworkCapabilities(@Nullable android.net.NetworkCapabilities);
@@ -336,6 +337,7 @@
public static class NetworkRequest.Builder {
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
+ method @NonNull public android.net.NetworkRequest.Builder setSubIds(@NonNull java.util.Set<java.lang.Integer>);
}
public final class NetworkScore implements android.os.Parcelable {
diff --git a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
index 4f95ccc..a54696f 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkCapabilities.java
@@ -2351,9 +2351,15 @@
/**
* Gets the subscription ID set that associated to this network or request.
+ *
+ * <p>Instances of NetworkCapabilities will only have this field populated by the system if the
+ * receiver holds the NETWORK_FACTORY permission. In all other cases, it will be the empty set.
+ *
* @return
+ * @hide
*/
@NonNull
+ @SystemApi
public Set<Integer> getSubIds() {
return new ArraySet<>(mSubIds);
}
@@ -2718,10 +2724,17 @@
/**
* Set the subscription ID set.
*
+ * <p>SubIds are populated in NetworkCapability instances from the system only for callers
+ * that hold the NETWORK_FACTORY permission. Similarly, the system will reject any
+ * NetworkRequests filed with a non-empty set of subIds unless the caller holds the
+ * NETWORK_FACTORY permission.
+ *
* @param subIds a set that represent the subscription IDs. Empty if clean up.
* @return this builder.
+ * @hide
*/
@NonNull
+ @SystemApi
public Builder setSubIds(@NonNull final Set<Integer> subIds) {
mCaps.setSubIds(subIds);
return this;
diff --git a/packages/Connectivity/framework/src/android/net/NetworkRequest.java b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
index 5313f08..3a8a07a 100644
--- a/packages/Connectivity/framework/src/android/net/NetworkRequest.java
+++ b/packages/Connectivity/framework/src/android/net/NetworkRequest.java
@@ -500,9 +500,14 @@
* A network will satisfy this request only if it matches one of the subIds in this set.
* An empty set matches all networks, including those without a subId.
*
+ * <p>Registering a NetworkRequest with a non-empty set of subIds requires the
+ * NETWORK_FACTORY permission.
+ *
* @param subIds A {@code Set} that represents subscription IDs.
+ * @hide
*/
@NonNull
+ @SystemApi
public Builder setSubIds(@NonNull Set<Integer> subIds) {
mNetworkCapabilities.setSubIds(subIds);
return this;
diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml
index fcc1aed..1125092 100644
--- a/packages/SystemUI/res/layout/notification_conversation_info.xml
+++ b/packages/SystemUI/res/layout/notification_conversation_info.xml
@@ -36,13 +36,62 @@
android:clipChildren="false"
android:paddingTop="@dimen/notification_guts_header_top_padding"
android:clipToPadding="true">
- <ImageView
- android:id="@+id/conversation_icon"
- android:layout_width="@dimen/notification_guts_conversation_icon_size"
- android:layout_height="@dimen/notification_guts_conversation_icon_size"
+ <FrameLayout
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:clipChildren="false"
+ android:clipToPadding="false"
android:layout_centerVertical="false"
android:layout_alignParentStart="true"
- android:layout_marginEnd="12dp" />
+ android:layout_marginEnd="12dp"
+ >
+
+ <!-- Big icon: 52x52, 12dp padding left + top, 16dp padding right -->
+ <ImageView
+ android:id="@+id/conversation_icon"
+ android:layout_width="@*android:dimen/conversation_avatar_size"
+ android:layout_height="@*android:dimen/conversation_avatar_size"
+ android:scaleType="centerCrop"
+ android:importantForAccessibility="no"
+ />
+
+ <FrameLayout
+ android:id="@+id/conversation_icon_badge"
+ android:layout_width="@*android:dimen/conversation_icon_size_badged"
+ android:layout_height="@*android:dimen/conversation_icon_size_badged"
+ android:layout_marginLeft="@*android:dimen/conversation_badge_side_margin"
+ android:layout_marginTop="@*android:dimen/conversation_badge_side_margin"
+ android:clipChildren="false"
+ android:clipToPadding="false"
+ >
+ <ImageView
+ android:id="@+id/conversation_icon_badge_bg"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_gravity="center"
+ android:src="@*android:drawable/conversation_badge_background"
+ android:forceHasOverlappingRendering="false"
+ />
+ <ImageView
+ android:id="@+id/conversation_icon_badge_icon"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:layout_margin="4dp"
+ android:layout_gravity="center"
+ android:forceHasOverlappingRendering="false"
+ />
+ <ImageView
+ android:id="@+id/conversation_icon_badge_ring"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:layout_gravity="center"
+ android:src="@*android:drawable/conversation_badge_ring"
+ android:forceHasOverlappingRendering="false"
+ android:clipToPadding="false"
+ android:scaleType="center"
+ />
+ </FrameLayout>
+ </FrameLayout>
<LinearLayout
android:id="@+id/names"
android:layout_weight="1"
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 6b7c628..2a2bb99 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -243,7 +243,7 @@
<dimen name="notification_guts_conversation_action_text_padding_start">32dp</dimen>
<dimen name="conversation_onboarding_bullet_gap_width">6dp</dimen>
- <dimen name="notification_guts_header_top_padding">11dp</dimen>
+ <dimen name="notification_guts_header_top_padding">12dp</dimen>
<!-- The height of the header in inline settings -->
<dimen name="notification_guts_header_height">24dp</dimen>
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
index b4ab8cf..8ba036c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java
@@ -346,9 +346,22 @@
}
private void bindIcon(boolean important) {
+ Drawable person = mIconFactory.getBaseIconDrawable(mShortcutInfo);
+ if (person == null) {
+ person = mContext.getDrawable(R.drawable.ic_person).mutate();
+ TypedArray ta = mContext.obtainStyledAttributes(new int[]{android.R.attr.colorAccent});
+ int colorAccent = ta.getColor(0, 0);
+ ta.recycle();
+ person.setTint(colorAccent);
+ }
ImageView image = findViewById(R.id.conversation_icon);
- image.setImageDrawable(mIconFactory.getConversationDrawable(
- mShortcutInfo, mPackageName, mAppUid, important));
+ image.setImageDrawable(person);
+
+ ImageView app = findViewById(R.id.conversation_icon_badge_icon);
+ app.setImageDrawable(mIconFactory.getAppBadge(
+ mPackageName, UserHandle.getUserId(mSbn.getUid())));
+
+ findViewById(R.id.conversation_icon_badge_ring).setVisibility(important ? VISIBLE : GONE);
}
private void bindPackage() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
index d4b21c6f..12e341a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java
@@ -199,8 +199,7 @@
when(mShortcutInfo.getLabel()).thenReturn("Convo name");
List<ShortcutInfo> shortcuts = Arrays.asList(mShortcutInfo);
when(mLauncherApps.getShortcuts(any(), any())).thenReturn(shortcuts);
- when(mIconFactory.getConversationDrawable(
- any(ShortcutInfo.class), anyString(), anyInt(), anyBoolean()))
+ when(mIconFactory.getBaseIconDrawable(any(ShortcutInfo.class)))
.thenReturn(mIconDrawable);
mNotificationChannel = new NotificationChannel(
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 57a93fa..aedf52d 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -1914,6 +1914,10 @@
newNc.setNetworkSpecifier(newNc.getNetworkSpecifier().redact());
}
newNc.setAdministratorUids(new int[0]);
+ if (!checkAnyPermissionOf(
+ callerPid, callerUid, android.Manifest.permission.NETWORK_FACTORY)) {
+ newNc.setSubIds(Collections.emptySet());
+ }
return newNc;
}
@@ -5667,6 +5671,10 @@
"Insufficient permissions to request a specific signal strength");
}
mAppOpsManager.checkPackage(callerUid, callerPackageName);
+
+ if (!nc.getSubIds().isEmpty()) {
+ enforceNetworkFactoryPermission();
+ }
}
private int[] getSignalStrengthThresholds(@NonNull final NetworkAgentInfo nai) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
index a5e6ddb..ca9be67 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/BiometricTestSessionImpl.java
@@ -48,7 +48,7 @@
*/
public class BiometricTestSessionImpl extends ITestSession.Stub {
- private static final String TAG = "BiometricTestSessionImpl";
+ private static final String TAG = "face/aidl/BiometricTestSessionImpl";
@NonNull private final Context mContext;
private final int mSensorId;
@@ -230,10 +230,12 @@
public void cleanupInternalState(int userId) {
Utils.checkPermission(mContext, TEST_BIOMETRIC);
+ Slog.d(TAG, "cleanupInternalState: " + userId);
mProvider.scheduleInternalCleanup(mSensorId, userId, new BaseClientMonitor.Callback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
try {
+ Slog.d(TAG, "onClientStarted: " + clientMonitor);
mCallback.onCleanupStarted(clientMonitor.getTargetUserId());
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
@@ -244,6 +246,7 @@
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
try {
+ Slog.d(TAG, "onClientFinished: " + clientMonitor);
mCallback.onCleanupFinished(clientMonitor.getTargetUserId());
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index a9be8e1..4fb71ff 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -49,7 +49,6 @@
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
-import com.android.server.biometrics.sensors.HalClientMonitor;
import com.android.server.biometrics.sensors.InvalidationRequesterClient;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
import com.android.server.biometrics.sensors.PerformanceTracker;
@@ -443,7 +442,7 @@
mContext.getOpPackageName(), sensorId, enrolledList,
FaceUtils.getInstance(sensorId),
mSensors.get(sensorId).getAuthenticatorIds());
- scheduleForSensor(sensorId, client);
+ scheduleForSensor(sensorId, client, callback);
});
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index 20b3254..1c88d67 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -45,7 +45,7 @@
*/
class BiometricTestSessionImpl extends ITestSession.Stub {
- private static final String TAG = "BiometricTestSessionImpl";
+ private static final String TAG = "fp/aidl/BiometricTestSessionImpl";
@NonNull private final Context mContext;
private final int mSensorId;
@@ -198,10 +198,12 @@
public void cleanupInternalState(int userId) {
Utils.checkPermission(mContext, TEST_BIOMETRIC);
+ Slog.d(TAG, "cleanupInternalState: " + userId);
mProvider.scheduleInternalCleanup(mSensorId, userId, new BaseClientMonitor.Callback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
try {
+ Slog.d(TAG, "onClientStarted: " + clientMonitor);
mCallback.onCleanupStarted(clientMonitor.getTargetUserId());
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
@@ -212,6 +214,7 @@
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
try {
+ Slog.d(TAG, "onClientFinished: " + clientMonitor);
mCallback.onCleanupFinished(clientMonitor.getTargetUserId());
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception", e);
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 24e867a..01fd641 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -432,7 +432,7 @@
mContext.getOpPackageName(), sensorId, enrolledList,
FingerprintUtils.getInstance(sensorId),
mSensors.get(sensorId).getAuthenticatorIds());
- scheduleForSensor(sensorId, client);
+ scheduleForSensor(sensorId, client, callback);
});
}
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 820198c..33224f4 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -102,7 +102,6 @@
import android.provider.Settings;
import android.security.Credentials;
import android.security.KeyStore2;
-import android.security.keystore.AndroidKeyStoreProvider;
import android.security.keystore.KeyProperties;
import android.system.keystore2.Domain;
import android.system.keystore2.KeyDescriptor;
@@ -2057,10 +2056,6 @@
if (alias == null) {
return null;
}
- // If Keystore 2.0 is not enabled the legacy private key prefix is used.
- if (!AndroidKeyStoreProvider.isKeystore2Enabled()) {
- return Credentials.USER_PRIVATE_KEY + alias;
- }
final KeyStore2 keystore2 = KeyStore2.getInstance();
KeyDescriptor key = new KeyDescriptor();
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 22a9a47..71a5d1c 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -98,6 +98,7 @@
import android.security.keystore.recovery.KeyChainSnapshot;
import android.security.keystore.recovery.RecoveryCertPath;
import android.security.keystore.recovery.WrappedApplicationKey;
+import android.security.keystore2.AndroidKeyStoreProvider;
import android.service.gatekeeper.GateKeeperResponse;
import android.service.gatekeeper.IGateKeeperService;
import android.text.TextUtils;
@@ -261,7 +262,7 @@
@Override
public void onStart() {
- android.security.keystore2.AndroidKeyStoreProvider.install();
+ AndroidKeyStoreProvider.install();
mLockSettingsService = new LockSettingsService(getContext());
publishBinderService("lock_settings", mLockSettingsService);
}
@@ -788,10 +789,6 @@
// Notify keystore that a new user was added.
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
AndroidKeyStoreMaintenance.onUserAdded(userHandle);
- final KeyStore ks = KeyStore.getInstance();
- final UserInfo parentInfo = mUserManager.getProfileParent(userHandle);
- final int parentHandle = parentInfo != null ? parentInfo.id : -1;
- ks.onUserAdded(userHandle, parentHandle);
} else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
mStorage.prefetchUser(userHandle);
@@ -1260,19 +1257,11 @@
private void setKeystorePassword(byte[] password, int userHandle) {
AndroidKeyStoreMaintenance.onUserPasswordChanged(userHandle, password);
- final KeyStore ks = KeyStore.getInstance();
- // TODO(b/120484642): Update keystore to accept byte[] passwords
- String passwordString = password == null ? null : new String(password);
- ks.onUserPasswordChanged(userHandle, passwordString);
}
private void unlockKeystore(byte[] password, int userHandle) {
if (DEBUG) Slog.v(TAG, "Unlock keystore for user: " + userHandle);
Authorization.onLockScreenEvent(false, userHandle, password);
- // TODO(b/120484642): Update keystore to accept byte[] passwords
- String passwordString = password == null ? null : new String(password);
- final KeyStore ks = KeyStore.getInstance();
- ks.unlock(userHandle, passwordString);
}
@VisibleForTesting /** Note: this method is overridden in unit tests */
@@ -2287,8 +2276,6 @@
mStrongAuth.removeUser(userId);
AndroidKeyStoreMaintenance.onUserRemoved(userId);
- final KeyStore ks = KeyStore.getInstance();
- ks.onUserRemoved(userId);
mManagedProfilePasswordCache.removePassword(userId);
gateKeeperClearSecureUserId(userId);
diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
index 7950fcf..fa477c8 100644
--- a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
+++ b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
@@ -20,10 +20,10 @@
import android.content.pm.UserInfo;
import android.os.UserHandle;
import android.os.UserManager;
-import android.security.keystore.AndroidKeyStoreSpi;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore.UserNotAuthenticatedException;
+import android.security.keystore2.AndroidKeyStoreSpi;
import android.util.Slog;
import android.util.SparseArray;
diff --git a/services/core/java/com/android/server/locksettings/RebootEscrowKeyStoreManager.java b/services/core/java/com/android/server/locksettings/RebootEscrowKeyStoreManager.java
index bae029c..da29368 100644
--- a/services/core/java/com/android/server/locksettings/RebootEscrowKeyStoreManager.java
+++ b/services/core/java/com/android/server/locksettings/RebootEscrowKeyStoreManager.java
@@ -16,11 +16,10 @@
package com.android.server.locksettings;
-import android.security.keystore.AndroidKeyStoreSpi;
import android.security.keystore.KeyGenParameterSpec;
import android.security.keystore.KeyProperties;
import android.security.keystore2.AndroidKeyStoreLoadStoreParameter;
-import android.security.keystore2.AndroidKeyStoreProvider;
+import android.security.keystore2.AndroidKeyStoreSpi;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
@@ -67,9 +66,7 @@
KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
KeyStore.LoadStoreParameter loadStoreParameter = null;
// Load from the specific namespace if keystore2 is enabled.
- if (AndroidKeyStoreProvider.isInstalled()) {
- loadStoreParameter = new AndroidKeyStoreLoadStoreParameter(KEY_STORE_NAMESPACE);
- }
+ loadStoreParameter = new AndroidKeyStoreLoadStoreParameter(KEY_STORE_NAMESPACE);
keyStore.load(loadStoreParameter);
return (SecretKey) keyStore.getKey(REBOOT_ESCROW_KEY_STORE_ENCRYPTION_KEY_NAME,
null);
@@ -91,9 +88,7 @@
KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);
KeyStore.LoadStoreParameter loadStoreParameter = null;
// Load from the specific namespace if keystore2 is enabled.
- if (AndroidKeyStoreProvider.isInstalled()) {
- loadStoreParameter = new AndroidKeyStoreLoadStoreParameter(KEY_STORE_NAMESPACE);
- }
+ loadStoreParameter = new AndroidKeyStoreLoadStoreParameter(KEY_STORE_NAMESPACE);
keyStore.load(loadStoreParameter);
keyStore.deleteEntry(REBOOT_ESCROW_KEY_STORE_ENCRYPTION_KEY_NAME);
} catch (IOException | GeneralSecurityException e) {
@@ -119,9 +114,7 @@
.setBlockModes(KeyProperties.BLOCK_MODE_GCM)
.setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE);
// Generate the key with the correct namespace if keystore2 is enabled.
- if (AndroidKeyStoreProvider.isInstalled()) {
- parameterSpecBuilder.setNamespace(KEY_STORE_NAMESPACE);
- }
+ parameterSpecBuilder.setNamespace(KEY_STORE_NAMESPACE);
generator.init(parameterSpecBuilder.build());
return generator.generateKey();
} catch (GeneralSecurityException e) {
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
index 2398f56..8582c67 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/storage/ApplicationKeyStorage.java
@@ -20,8 +20,6 @@
import android.annotation.Nullable;
import android.os.ServiceSpecificException;
-import android.security.Credentials;
-import android.security.KeyStore;
import android.security.KeyStore2;
import android.security.keystore.KeyProperties;
import android.security.keystore.KeyProtection;
@@ -75,13 +73,7 @@
public @Nullable String getGrantAlias(int userId, int uid, String alias) {
Log.i(TAG, String.format(Locale.US, "Get %d/%d/%s", userId, uid, alias));
String keystoreAlias = getInternalAlias(userId, uid, alias);
- if (useKeyStore2()) {
- return makeKeystoreEngineGrantString(uid, keystoreAlias);
- } else {
- // Aliases used by {@link KeyStore} are different than used by public API.
- // {@code USER_PRIVATE_KEY} prefix is used secret keys.
- return KeyStore.getInstance().grant(Credentials.USER_PRIVATE_KEY + keystoreAlias, uid);
- }
+ return makeKeystoreEngineGrantString(uid, keystoreAlias);
}
public void setSymmetricKeyEntry(int userId, int uid, String alias, byte[] secretKey)
@@ -148,9 +140,4 @@
}
return String.format("%s%016X", APPLICATION_KEY_GRANT_PREFIX, key.nspace);
}
-
- private static boolean useKeyStore2() {
- return android.security.keystore2.AndroidKeyStoreProvider.isInstalled();
- }
-
}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 4fbc795..f014b07 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -56,7 +56,6 @@
import android.os.UserManager;
import android.provider.Settings;
import android.security.Authorization;
-import android.security.KeyStore;
import android.service.trust.TrustAgentService;
import android.text.TextUtils;
import android.util.ArrayMap;
@@ -704,13 +703,11 @@
dispatchDeviceLocked(userId, locked);
Authorization.onLockScreenEvent(locked, userId, null);
- KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
// Also update the user's profiles who have unified challenge, since they
// share the same unlocked state (see {@link #isDeviceLocked(int)})
for (int profileHandle : mUserManager.getEnabledProfileIds(userId)) {
if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(profileHandle)) {
mAuthorizationService.onLockScreenEvent(locked, profileHandle, null);
- KeyStore.getInstance().onUserLockedStateChanged(profileHandle, locked);
}
}
}
@@ -1262,7 +1259,6 @@
}
Authorization.onLockScreenEvent(locked, userId, null);
- KeyStore.getInstance().onUserLockedStateChanged(userId, locked);
if (locked) {
try {
diff --git a/telephony/java/com/android/internal/telephony/DctConstants.java b/telephony/java/com/android/internal/telephony/DctConstants.java
index 541292a..1e5d598 100644
--- a/telephony/java/com/android/internal/telephony/DctConstants.java
+++ b/telephony/java/com/android/internal/telephony/DctConstants.java
@@ -130,4 +130,5 @@
public static final String RAT_NAME_LTE = "LTE";
public static final String RAT_NAME_NR_NSA = "NR_NSA";
public static final String RAT_NAME_NR_NSA_MMWAVE = "NR_NSA_MMWAVE";
+ public static final String RAT_NAME_NR_SA_MMWAVE = "NR_MMWAVE";
}
diff --git a/tests/ActivityManagerPerfTests/tests/Android.bp b/tests/ActivityManagerPerfTests/tests/Android.bp
index c8dbf81..e5813ae 100644
--- a/tests/ActivityManagerPerfTests/tests/Android.bp
+++ b/tests/ActivityManagerPerfTests/tests/Android.bp
@@ -28,6 +28,7 @@
"androidx.test.rules",
"apct-perftests-utils",
"ActivityManagerPerfTestsUtils",
+ "collector-device-lib-platform",
],
platform_apis: true,
min_sdk_version: "25",
diff --git a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
index 475bb82..e753b70 100644
--- a/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
+++ b/tests/ActivityManagerPerfTests/tests/AndroidTest.xml
@@ -28,5 +28,22 @@
<test class="com.android.tradefed.testtype.AndroidJUnitTest">
<option name="package" value="com.android.frameworks.perftests.amtests"/>
<option name="runner" value="androidx.test.runner.AndroidJUnitRunner"/>
+
+ <!-- TODO: Add PerfettoListener to automatically capture perfetto traces for each test-->
+ <!-- Listener related args for collecting the traces and waiting for the device
+ to stabilize. -->
+ <option name="device-listeners"
+ value="android.device.collectors.ProcLoadListener" />
+ <!-- Guarantee that user defined RunListeners will be running before any of the default
+ listeners defined in this runner. -->
+ <option name="instrumentation-arg" key="newRunListenerMode" value="true" />
+
+ <!-- ProcLoadListener related arguments -->
+ <!-- Wait for device last minute threshold to reach 3 with 2 minute timeout before
+ starting the test run -->
+ <option name="instrumentation-arg" key="procload-collector:per_run" value="true" />
+ <option name="instrumentation-arg" key="proc-loadavg-threshold" value="3" />
+ <option name="instrumentation-arg" key="proc-loadavg-timeout" value="120000" />
+ <option name="instrumentation-arg" key="proc-loadavg-interval" value="10000" />
</test>
</configuration>
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index b15d252..4c5e64c 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -18,6 +18,7 @@
import static android.Manifest.permission.CHANGE_NETWORK_STATE;
import static android.Manifest.permission.CONNECTIVITY_USE_RESTRICTED_NETWORKS;
+import static android.Manifest.permission.NETWORK_FACTORY;
import static android.Manifest.permission.NETWORK_SETTINGS;
import static android.app.PendingIntent.FLAG_IMMUTABLE;
import static android.content.Intent.ACTION_USER_ADDED;
@@ -12474,4 +12475,68 @@
mCm.setProfileNetworkPreference(testHandle,
PROFILE_NETWORK_PREFERENCE_ENTERPRISE, null, null));
}
+
+ @Test
+ public void testSubIdsClearedWithoutNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ nc.setSubIds(Collections.singleton(Process.myUid()));
+
+ final NetworkCapabilities result =
+ mService.networkCapabilitiesRestrictedForCallerPermissions(
+ nc, Process.myPid(), Process.myUid());
+ assertTrue(result.getSubIds().isEmpty());
+ }
+
+ @Test
+ public void testSubIdsExistWithNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
+
+ final Set<Integer> subIds = Collections.singleton(Process.myUid());
+ final NetworkCapabilities nc = new NetworkCapabilities();
+ nc.setSubIds(subIds);
+
+ final NetworkCapabilities result =
+ mService.networkCapabilitiesRestrictedForCallerPermissions(
+ nc, Process.myPid(), Process.myUid());
+ assertEquals(subIds, result.getSubIds());
+ }
+
+ private NetworkRequest getRequestWithSubIds() {
+ return new NetworkRequest.Builder()
+ .setSubIds(Collections.singleton(Process.myUid()))
+ .build();
+ }
+
+ @Test
+ public void testNetworkRequestWithSubIdsWithNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_GRANTED);
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
+ final NetworkCallback networkCallback1 = new NetworkCallback();
+ final NetworkCallback networkCallback2 = new NetworkCallback();
+
+ mCm.requestNetwork(getRequestWithSubIds(), networkCallback1);
+ mCm.requestNetwork(getRequestWithSubIds(), pendingIntent);
+ mCm.registerNetworkCallback(getRequestWithSubIds(), networkCallback2);
+
+ mCm.unregisterNetworkCallback(networkCallback1);
+ mCm.releaseNetworkRequest(pendingIntent);
+ mCm.unregisterNetworkCallback(networkCallback2);
+ }
+
+ @Test
+ public void testNetworkRequestWithSubIdsWithoutNetworkFactoryPermission() throws Exception {
+ mServiceContext.setPermission(NETWORK_FACTORY, PERMISSION_DENIED);
+ final PendingIntent pendingIntent = PendingIntent.getBroadcast(
+ mContext, 0 /* requestCode */, new Intent("a"), FLAG_IMMUTABLE);
+
+ final Class<SecurityException> expected = SecurityException.class;
+ assertThrows(
+ expected, () -> mCm.requestNetwork(getRequestWithSubIds(), new NetworkCallback()));
+ assertThrows(expected, () -> mCm.requestNetwork(getRequestWithSubIds(), pendingIntent));
+ assertThrows(
+ expected,
+ () -> mCm.registerNetworkCallback(getRequestWithSubIds(), new NetworkCallback()));
+ }
}