Merge "Make Settings aware of legacy user keys with secret key prefix"

This commit is contained in:
Janis Danisevskis
2017-12-15 23:48:55 +00:00
committed by Android (Google) Code Review
2 changed files with 53 additions and 27 deletions

View File

@@ -37,6 +37,8 @@ import android.security.IKeyChainService;
import android.security.KeyChain; import android.security.KeyChain;
import android.security.KeyChain.KeyChainConnection; import android.security.KeyChain.KeyChainConnection;
import android.security.KeyStore; import android.security.KeyStore;
import android.security.keymaster.KeyCharacteristics;
import android.security.keymaster.KeymasterDefs;
import android.support.v7.widget.RecyclerView; import android.support.v7.widget.RecyclerView;
import android.util.Log; import android.util.Log;
import android.util.SparseArray; import android.util.SparseArray;
@@ -48,19 +50,15 @@ import android.widget.TextView;
import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.widget.LockPatternUtils; import com.android.internal.widget.LockPatternUtils;
import com.android.settings.core.instrumentation.InstrumentedDialogFragment; import com.android.settings.core.instrumentation.InstrumentedDialogFragment;
import com.android.settings.SettingsPreferenceFragment;
import com.android.settingslib.RestrictedLockUtils; import com.android.settingslib.RestrictedLockUtils;
import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin; import com.android.settingslib.RestrictedLockUtils.EnforcedAdmin;
import java.security.UnrecoverableKeyException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.EnumSet; import java.util.EnumSet;
import java.util.List; import java.util.List;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
public class UserCredentialsSettings extends SettingsPreferenceFragment public class UserCredentialsSettings extends SettingsPreferenceFragment
implements View.OnClickListener { implements View.OnClickListener {
private static final String TAG = "UserCredentialsSettings"; private static final String TAG = "UserCredentialsSettings";
@@ -254,27 +252,57 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment
return credentials; 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<String, Credential> getCredentialsForUid(KeyStore keyStore, int uid) { private SortedMap<String, Credential> getCredentialsForUid(KeyStore keyStore, int uid) {
final SortedMap<String, Credential> aliasMap = new TreeMap<>(); final SortedMap<String, Credential> aliasMap = new TreeMap<>();
for (final Credential.Type type : Credential.Type.values()) { for (final Credential.Type type : Credential.Type.values()) {
for (final String alias : keyStore.list(type.prefix, uid)) { for (final String prefix : type.prefix) {
if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) { for (final String alias : keyStore.list(prefix, uid)) {
// Do not show work profile keys in user credentials if (UserHandle.getAppId(uid) == Process.SYSTEM_UID) {
if (alias.startsWith(LockPatternUtils.PROFILE_KEY_NAME_ENCRYPT) || // Do not show work profile keys in user credentials
alias.startsWith(LockPatternUtils.PROFILE_KEY_NAME_DECRYPT)) { 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; continue;
} }
// Do not show synthetic password keys in user credential Credential c = aliasMap.get(alias);
if (alias.startsWith(LockPatternUtils.SYNTHETIC_PASSWORD_KEY_PREFIX)) { if (c == null) {
continue; 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; return aliasMap;
@@ -344,7 +372,7 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment
*/ */
private static final SparseArray<Credential.Type> credentialViewTypes = new SparseArray<>(); private static final SparseArray<Credential.Type> credentialViewTypes = new SparseArray<>();
static { 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_usercrt, Credential.Type.USER_CERTIFICATE);
credentialViewTypes.put(R.id.contents_cacrt, Credential.Type.CA_CERTIFICATE); credentialViewTypes.put(R.id.contents_cacrt, Credential.Type.CA_CERTIFICATE);
} }
@@ -380,12 +408,11 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment
static enum Type { static enum Type {
CA_CERTIFICATE (Credentials.CA_CERTIFICATE), CA_CERTIFICATE (Credentials.CA_CERTIFICATE),
USER_CERTIFICATE (Credentials.USER_CERTIFICATE), USER_CERTIFICATE (Credentials.USER_CERTIFICATE),
USER_PRIVATE_KEY (Credentials.USER_PRIVATE_KEY), USER_KEY(Credentials.USER_PRIVATE_KEY, Credentials.USER_SECRET_KEY);
USER_SECRET_KEY (Credentials.USER_SECRET_KEY);
final String prefix; final String[] prefix;
Type(String prefix) { Type(String... prefix) {
this.prefix = prefix; this.prefix = prefix;
} }
} }
@@ -407,8 +434,7 @@ public class UserCredentialsSettings extends SettingsPreferenceFragment
* <ul> * <ul>
* <li>{@link Credentials.CA_CERTIFICATE}</li> * <li>{@link Credentials.CA_CERTIFICATE}</li>
* <li>{@link Credentials.USER_CERTIFICATE}</li> * <li>{@link Credentials.USER_CERTIFICATE}</li>
* <li>{@link Credentials.USER_PRIVATE_KEY}</li> * <li>{@link Credentials.USER_KEY}</li>
* <li>{@link Credentials.USER_SECRET_KEY}</li>
* </ul> * </ul>
*/ */
final EnumSet<Type> storedTypes = EnumSet.noneOf(Type.class); final EnumSet<Type> storedTypes = EnumSet.noneOf(Type.class);

View File

@@ -40,7 +40,7 @@ public class UserCredentialsTest extends InstrumentationTestCase {
Credential c = new Credential(alias, Process.SYSTEM_UID); Credential c = new Credential(alias, Process.SYSTEM_UID);
c.storedTypes.add(Credential.Type.CA_CERTIFICATE); 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(); Parcel p = Parcel.obtain();
c.writeToParcel(p, /* flags */ 0); c.writeToParcel(p, /* flags */ 0);