From 607a995691dcda1475042ddcd4e4cba708c791be Mon Sep 17 00:00:00 2001 From: Eran Messeri Date: Mon, 9 Jul 2018 17:58:26 +0100 Subject: [PATCH] DPM: Propagate StrongBox-related exception When the caller attempts to generate a key via DevicePolicyManager (using DevicePolicyManager.generateKeyPair), and specifies that StrongBox should be used, throw the right exception indicating StrongBox unavailability - the same one that is thrown if the same parameters were passed to the KeyStore's key generation method. This is achieved by catching the StrongBoxUnavailableException in KeyChain, returning an error code indicating this particular failure to the DevicePolicyManagerService, which then propagates it by throwing a service-specific exception with a value indicating StrongBox unavailability. The DevicePolicyManager then raises StrongBoxUnavailableException. Prior to this change the exception propagated from KeyChain would be a generic failure so the caller would simply get a null result. Bug: 110882855 Bug: 111183576 Bug: 111322478 Test: atest CtsDevicePolicyManagerTestCases:com.android.cts.devicepolicy.MixedDeviceOwnerTest#testKeyManagement Change-Id: I9abe3f449b48eb5a960fafbc15c59b9b4ce7a966 --- .../app/admin/DevicePolicyManager.java | 19 +++++++++++++++++++ keystore/java/android/security/KeyChain.java | 8 +++++++- .../DevicePolicyManagerService.java | 9 ++++++++- 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index bbdc5323648d0..cbd874176586c 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -72,6 +72,7 @@ import android.security.keystore.AttestationUtils; import android.security.keystore.KeyAttestationException; import android.security.keystore.KeyGenParameterSpec; import android.security.keystore.ParcelableKeyGenParameterSpec; +import android.security.keystore.StrongBoxUnavailableException; import android.service.restrictions.RestrictionsReceiver; import android.telephony.TelephonyManager; import android.telephony.data.ApnSetting; @@ -1773,6 +1774,13 @@ public class DevicePolicyManager { */ public static final int ID_TYPE_MEID = 8; + /** + * Service-specific error code for {@link #generateKeyPair}: + * Indicates the call has failed due to StrongBox unavailability. + * @hide + */ + public static final int KEY_GEN_STRONGBOX_UNAVAILABLE = 1; + /** * Specifies that the calling app should be granted access to the installed credentials * immediately. Otherwise, access to the credentials will be gated by user approval. @@ -4190,6 +4198,8 @@ public class DevicePolicyManager { * {@code keySpec} does not contain an attestation challenge. * @throws UnsupportedOperationException if Device ID attestation was requested but the * underlying hardware does not support it. + * @throws StrongBoxUnavailableException if the use of StrongBox for key generation was + * specified in {@code keySpec} but the device does not have one. * @see KeyGenParameterSpec.Builder#setAttestationChallenge(byte[]) */ public AttestedKeyPair generateKeyPair(@Nullable ComponentName admin, @@ -4230,6 +4240,15 @@ public class DevicePolicyManager { } catch (InterruptedException e) { Log.w(TAG, "Interrupted while generating key", e); Thread.currentThread().interrupt(); + } catch (ServiceSpecificException e) { + Log.w(TAG, String.format("Key Generation failure: %d", e.errorCode)); + switch (e.errorCode) { + case KEY_GEN_STRONGBOX_UNAVAILABLE: + throw new StrongBoxUnavailableException("No StrongBox for key generation."); + default: + throw new RuntimeException( + String.format("Unknown error while generating key: %d", e.errorCode)); + } } return null; } diff --git a/keystore/java/android/security/KeyChain.java b/keystore/java/android/security/KeyChain.java index 030fa60abfd3f..78dbb6ae0df3a 100644 --- a/keystore/java/android/security/KeyChain.java +++ b/keystore/java/android/security/KeyChain.java @@ -282,11 +282,17 @@ public final class KeyChain { */ public static final int KEY_GEN_NO_KEYSTORE_PROVIDER = 5; + /** + * StrongBox unavailable when calling {@link #generateKeyPair} + * @hide + */ + public static final int KEY_GEN_STRONGBOX_UNAVAILABLE = 6; + /** * General failure while calling {@link #generateKeyPair} * @hide */ - public static final int KEY_GEN_FAILURE = 6; + public static final int KEY_GEN_FAILURE = 7; /** * Successful call to {@link #attestKey} diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 9ef806e807331..ed4d4db39db37 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -5465,7 +5465,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (generationResult != KeyChain.KEY_GEN_SUCCESS) { Log.e(LOG_TAG, String.format( "KeyChain failed to generate a keypair, error %d.", generationResult)); - return false; + switch (generationResult) { + case KeyChain.KEY_GEN_STRONGBOX_UNAVAILABLE: + throw new ServiceSpecificException( + DevicePolicyManager.KEY_GEN_STRONGBOX_UNAVAILABLE, + String.format("KeyChain error: %d", generationResult)); + default: + return false; + } } // Set a grant for the caller here so that when the client calls