From b705e1a69128860557cdf963e4dec53f159d9a4a Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Wed, 19 Apr 2017 16:23:02 -0700 Subject: [PATCH] Make Settings aware of legacy user keys with secret key prefix Secret keys are not longer identifiable by their alias prefix. So now we call getKeyCharacteristics and check the algorithm of the key. Bug: 63931634 Test: Manually installed a key and checked that it is still dispayed correctly. Change-Id: I55a4e46434618cb52ceb9456f184e004165872fd --- .../settings/UserCredentialsSettings.java | 78 ++++++++++++------- .../android/settings/UserCredentialsTest.java | 2 +- 2 files changed, 53 insertions(+), 27 deletions(-) diff --git a/src/com/android/settings/UserCredentialsSettings.java b/src/com/android/settings/UserCredentialsSettings.java index 54e12a85faa..7d0fca07f1f 100644 --- a/src/com/android/settings/UserCredentialsSettings.java +++ b/src/com/android/settings/UserCredentialsSettings.java @@ -37,6 +37,8 @@ import android.security.IKeyChainService; import android.security.KeyChain; import android.security.KeyChain.KeyChainConnection; import android.security.KeyStore; +import android.security.keymaster.KeyCharacteristics; +import android.security.keymaster.KeymasterDefs; import android.support.v7.widget.RecyclerView; import android.util.Log; import android.util.SparseArray; @@ -48,19 +50,15 @@ import android.widget.TextView; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.widget.LockPatternUtils; import com.android.settings.core.instrumentation.InstrumentedDialogFragment; -import com.android.settings.SettingsPreferenceFragment; import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; - +import java.security.UnrecoverableKeyException; import java.util.ArrayList; import java.util.EnumSet; import java.util.List; import java.util.SortedMap; import java.util.TreeMap; -import static android.view.View.GONE; -import static android.view.View.VISIBLE; - public class UserCredentialsSettings extends SettingsPreferenceFragment implements View.OnClickListener { private static final String TAG = "UserCredentialsSettings"; @@ -254,27 +252,57 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment return credentials; } + private boolean isAsymmetric(KeyStore keyStore, String alias, int uid) + throws UnrecoverableKeyException { + KeyCharacteristics keyCharacteristics = new KeyCharacteristics(); + int errorCode = keyStore.getKeyCharacteristics(alias, null, null, uid, + keyCharacteristics); + if (errorCode != KeyStore.NO_ERROR) { + throw (UnrecoverableKeyException) + new UnrecoverableKeyException("Failed to obtain information about key") + .initCause(KeyStore.getKeyStoreException(errorCode)); + } + Integer keymasterAlgorithm = keyCharacteristics.getEnum( + KeymasterDefs.KM_TAG_ALGORITHM); + if (keymasterAlgorithm == null) { + throw new UnrecoverableKeyException("Key algorithm unknown"); + } + return keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_RSA || + keymasterAlgorithm == KeymasterDefs.KM_ALGORITHM_EC; + } + private SortedMap getCredentialsForUid(KeyStore keyStore, int uid) { final SortedMap aliasMap = new TreeMap<>(); for (final Credential.Type type : Credential.Type.values()) { - for (final String alias : keyStore.list(type.prefix, uid)) { - if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) { - // Do not show work profile keys in user credentials - if (alias.startsWith(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT) || - alias.startsWith(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT)) { + for (final String prefix : type.prefix) { + for (final String alias : keyStore.list(prefix, uid)) { + if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) { + // Do not show work profile keys in user credentials + if (alias.startsWith(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT) || + alias.startsWith(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT)) { + continue; + } + // Do not show synthetic password keys in user credential + if (alias.startsWith(LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX)) { + continue; + } + } + try { + if (type == Credential.Type.USER_KEY && + !isAsymmetric(keyStore, prefix + alias, uid)) { + continue; + } + } catch (UnrecoverableKeyException e) { + Log.e(TAG, "Unable to determine algorithm of key: " + prefix + alias, e); continue; } - // Do not show synthetic password keys in user credential - if (alias.startsWith(LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX)) { - continue; + Credential c = aliasMap.get(alias); + if (c == null) { + c = new Credential(alias, uid); + aliasMap.put(alias, c); } + c.storedTypes.add(type); } - Credential c = aliasMap.get(alias); - if (c == null) { - c = new Credential(alias, uid); - aliasMap.put(alias, c); - } - c.storedTypes.add(type); } } return aliasMap; @@ -344,7 +372,7 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment */ private static final SparseArray credentialViewTypes = new SparseArray<>(); static { - credentialViewTypes.put(R.id.contents_userkey, Credential.Type.USER_PRIVATE_KEY); + credentialViewTypes.put(R.id.contents_userkey, Credential.Type.USER_KEY); credentialViewTypes.put(R.id.contents_usercrt, Credential.Type.USER_CERTIFICATE); credentialViewTypes.put(R.id.contents_cacrt, Credential.Type.CA_CERTIFICATE); } @@ -380,12 +408,11 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment static enum Type { CA_CERTIFICATE (Credentials.CA_CERTIFICATE), USER_CERTIFICATE (Credentials.USER_CERTIFICATE), - USER_PRIVATE_KEY (Credentials.USER_PRIVATE_KEY), - USER_SECRET_KEY (Credentials.USER_SECRET_KEY); + USER_KEY(Credentials.USER_PRIVATE_KEY, Credentials.USER_SECRET_KEY); - final String prefix; + final String[] prefix; - Type(String prefix) { + Type(String... prefix) { this.prefix = prefix; } } @@ -407,8 +434,7 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment *
    *
  • {@link Credentials.CA_CERTIFICATE}
  • *
  • {@link Credentials.USER_CERTIFICATE}
  • - *
  • {@link Credentials.USER_PRIVATE_KEY}
  • - *
  • {@link Credentials.USER_SECRET_KEY}
  • + *
  • {@link Credentials.USER_KEY}
  • *
*/ final EnumSet storedTypes = EnumSet.noneOf(Type.class); diff --git a/tests/unit/src/com/android/settings/UserCredentialsTest.java b/tests/unit/src/com/android/settings/UserCredentialsTest.java index 41ef4dec2f5..8a72797e2cb 100644 --- a/tests/unit/src/com/android/settings/UserCredentialsTest.java +++ b/tests/unit/src/com/android/settings/UserCredentialsTest.java @@ -40,7 +40,7 @@ public class UserCredentialsTest extends InstrumentationTestCase { Credential c = new Credential(alias, Process.SYSTEM_UID); c.storedTypes.add(Credential.Type.CA_CERTIFICATE); - c.storedTypes.add(Credential.Type.USER_SECRET_KEY); + c.storedTypes.add(Credential.Type.USER_KEY); Parcel p = Parcel.obtain(); c.writeToParcel(p, /* flags */ 0);