From 146a0dab0144a348fefce24296ebfd1256ce0d72 Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Mon, 25 Jan 2021 14:59:38 -0800 Subject: [PATCH] Keystore 2.0: Make Legacy VPN settings ready for Keystore 2.0 Keystore 2.0 no longer stores vpn profiles. It still offers a Legacy VPN profile store, to access existing profiles. Test: N/A Bug: 171305607 Bug: 171305388 Merged-In: I40dea0b9c3824b56814ae4c2fb6c7663c7d97af5 Change-Id: I40dea0b9c3824b56814ae4c2fb6c7663c7d97af5 --- .../utils/AndroidKeystoreAliasLoader.java | 5 +++ .../android/settings/vpn2/ConfigDialog.java | 40 +++++++++++-------- .../settings/vpn2/ConfigDialogFragment.java | 10 ++--- .../android/settings/vpn2/VpnSettings.java | 16 ++++---- src/com/android/settings/vpn2/VpnUtils.java | 12 +++--- 5 files changed, 44 insertions(+), 39 deletions(-) diff --git a/src/com/android/settings/utils/AndroidKeystoreAliasLoader.java b/src/com/android/settings/utils/AndroidKeystoreAliasLoader.java index b9ccf291b74..bb9abb981be 100644 --- a/src/com/android/settings/utils/AndroidKeystoreAliasLoader.java +++ b/src/com/android/settings/utils/AndroidKeystoreAliasLoader.java @@ -28,6 +28,7 @@ import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.UnrecoverableKeyException; +import java.security.cert.Certificate; import java.util.ArrayList; import java.util.Collection; import java.util.Enumeration; @@ -88,6 +89,10 @@ public class AndroidKeystoreAliasLoader { if (key != null) { if (key instanceof PrivateKey) { mKeyCertAliases.add(alias); + final Certificate[] cert = keyStore.getCertificateChain(alias); + if (cert != null && cert.length >= 2) { + mCaCertAliases.add(alias); + } } } else { if (keyStore.getCertificate(alias) != null) { diff --git a/src/com/android/settings/vpn2/ConfigDialog.java b/src/com/android/settings/vpn2/ConfigDialog.java index a0c7a1e92fe..42bc67dc15a 100644 --- a/src/com/android/settings/vpn2/ConfigDialog.java +++ b/src/com/android/settings/vpn2/ConfigDialog.java @@ -24,8 +24,6 @@ import android.content.pm.PackageManager; import android.net.ProxyInfo; import android.os.Bundle; import android.os.SystemProperties; -import android.security.Credentials; -import android.security.KeyStore; import android.text.Editable; import android.text.TextWatcher; import android.view.View; @@ -42,10 +40,12 @@ import androidx.appcompat.app.AlertDialog; import com.android.internal.net.VpnProfile; import com.android.net.module.util.ProxyUtils; import com.android.settings.R; +import com.android.settings.utils.AndroidKeystoreAliasLoader; import java.net.InetAddress; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.List; /** @@ -58,7 +58,7 @@ import java.util.List; class ConfigDialog extends AlertDialog implements TextWatcher, View.OnClickListener, AdapterView.OnItemSelectedListener, CompoundButton.OnCheckedChangeListener { - private final KeyStore mKeyStore = KeyStore.getInstance(); + private static final String TAG = "ConfigDialog"; private final DialogInterface.OnClickListener mListener; private final VpnProfile mProfile; @@ -153,10 +153,13 @@ class ConfigDialog extends AlertDialog implements TextWatcher, mL2tpSecret.setTextAppearance(android.R.style.TextAppearance_DeviceDefault_Medium); mIpsecIdentifier.setText(mProfile.ipsecIdentifier); mIpsecSecret.setText(mProfile.ipsecSecret); - loadCertificates(mIpsecUserCert, Credentials.USER_PRIVATE_KEY, 0, mProfile.ipsecUserCert); - loadCertificates(mIpsecCaCert, Credentials.CA_CERTIFICATE, + AndroidKeystoreAliasLoader androidKeystoreAliasLoader = + new AndroidKeystoreAliasLoader(null); + loadCertificates(mIpsecUserCert, androidKeystoreAliasLoader.getKeyCertAliases(), 0, + mProfile.ipsecUserCert); + loadCertificates(mIpsecCaCert, androidKeystoreAliasLoader.getCaCertAliases(), R.string.vpn_no_ca_cert, mProfile.ipsecCaCert); - loadCertificates(mIpsecServerCert, Credentials.USER_CERTIFICATE, + loadCertificates(mIpsecServerCert, androidKeystoreAliasLoader.getKeyCertAliases(), R.string.vpn_no_server_cert, mProfile.ipsecServerCert); mSaveLogin.setChecked(mProfile.saveLogin); mAlwaysOnVpn.setChecked(mProfile.key.equals(VpnUtils.getLockdownVpn())); @@ -511,27 +514,30 @@ class ConfigDialog extends AlertDialog implements TextWatcher, typeSpinner.setAdapter(adapter); } - private void loadCertificates(Spinner spinner, String prefix, int firstId, String selected) { + private void loadCertificates(Spinner spinner, Collection choices, int firstId, + String selected) { Context context = getContext(); String first = (firstId == 0) ? "" : context.getString(firstId); - String[] certificates = mKeyStore.list(prefix); + String[] myChoices; - if (certificates == null || certificates.length == 0) { - certificates = new String[] {first}; + if (choices == null || choices.size() == 0) { + myChoices = new String[] {first}; } else { - String[] array = new String[certificates.length + 1]; - array[0] = first; - System.arraycopy(certificates, 0, array, 1, certificates.length); - certificates = array; + myChoices = new String[choices.size() + 1]; + myChoices[0] = first; + int i = 1; + for (String c : choices) { + myChoices[i++] = c; + } } ArrayAdapter adapter = new ArrayAdapter( - context, android.R.layout.simple_spinner_item, certificates); + context, android.R.layout.simple_spinner_item, myChoices); adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item); spinner.setAdapter(adapter); - for (int i = 1; i < certificates.length; ++i) { - if (certificates[i].equals(selected)) { + for (int i = 1; i < myChoices.length; ++i) { + if (myChoices[i].equals(selected)) { spinner.setSelection(i); break; } diff --git a/src/com/android/settings/vpn2/ConfigDialogFragment.java b/src/com/android/settings/vpn2/ConfigDialogFragment.java index f339a694c03..b8825fed6b8 100644 --- a/src/com/android/settings/vpn2/ConfigDialogFragment.java +++ b/src/com/android/settings/vpn2/ConfigDialogFragment.java @@ -25,7 +25,7 @@ import android.os.Bundle; import android.os.RemoteException; import android.os.UserHandle; import android.security.Credentials; -import android.security.KeyStore; +import android.security.LegacyVpnProfileStore; import android.util.Log; import android.view.View; import android.widget.Toast; @@ -151,9 +151,8 @@ public class ConfigDialogFragment extends InstrumentedDialogFragment implements return; } - // Delete from KeyStore - KeyStore keyStore = KeyStore.getInstance(); - keyStore.delete(Credentials.VPN + profile.key, KeyStore.UID_SELF); + // Delete from profile store. + LegacyVpnProfileStore.remove(Credentials.VPN + profile.key); updateLockdownVpn(false, profile); } @@ -188,8 +187,7 @@ public class ConfigDialogFragment extends InstrumentedDialogFragment implements } private void save(VpnProfile profile, boolean lockdown) { - KeyStore.getInstance().put(Credentials.VPN + profile.key, profile.encode(), - KeyStore.UID_SELF, /* flags */ 0); + LegacyVpnProfileStore.put(Credentials.VPN + profile.key, profile.encode()); // Flush out old version of profile disconnect(profile); diff --git a/src/com/android/settings/vpn2/VpnSettings.java b/src/com/android/settings/vpn2/VpnSettings.java index 0a3b2b01cd7..7635733d77f 100644 --- a/src/com/android/settings/vpn2/VpnSettings.java +++ b/src/com/android/settings/vpn2/VpnSettings.java @@ -41,7 +41,7 @@ import android.os.Message; import android.os.UserHandle; import android.os.UserManager; import android.security.Credentials; -import android.security.KeyStore; +import android.security.LegacyVpnProfileStore; import android.util.ArrayMap; import android.util.ArraySet; import android.util.Log; @@ -57,7 +57,6 @@ import com.android.internal.annotations.GuardedBy; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; import com.android.internal.net.VpnProfile; -import com.android.internal.util.ArrayUtils; import com.android.settings.R; import com.android.settings.RestrictedSettingsFragment; import com.android.settings.widget.GearPreference; @@ -94,8 +93,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements private UserManager mUserManager; private VpnManager mVpnManager; - private final KeyStore mKeyStore = KeyStore.getInstance(); - private Map mLegacyVpnPreferences = new ArrayMap<>(); private Map mAppPreferences = new ArrayMap<>(); @@ -222,7 +219,7 @@ public class VpnSettings extends RestrictedSettingsFragment implements final Context context = activity.getApplicationContext(); // Run heavy RPCs before switching to UI thread - final List vpnProfiles = loadVpnProfiles(mKeyStore); + final List vpnProfiles = loadVpnProfiles(); final List vpnApps = getVpnApps(context, /* includeProfiles */ true); final Map connectedLegacyVpns = getConnectedLegacyVpns(); @@ -540,12 +537,13 @@ public class VpnSettings extends RestrictedSettingsFragment implements return result; } - static List loadVpnProfiles(KeyStore keyStore, int... excludeTypes) { + private static List loadVpnProfiles() { final ArrayList result = Lists.newArrayList(); - for (String key : keyStore.list(Credentials.VPN)) { - final VpnProfile profile = VpnProfile.decode(key, keyStore.get(Credentials.VPN + key)); - if (profile != null && !ArrayUtils.contains(excludeTypes, profile.type)) { + for (String key : LegacyVpnProfileStore.list(Credentials.VPN)) { + final VpnProfile profile = VpnProfile.decode(key, + LegacyVpnProfileStore.get(Credentials.VPN + key)); + if (profile != null) { result.add(profile); } } diff --git a/src/com/android/settings/vpn2/VpnUtils.java b/src/com/android/settings/vpn2/VpnUtils.java index 4c9338ccd68..d6a55781b5e 100644 --- a/src/com/android/settings/vpn2/VpnUtils.java +++ b/src/com/android/settings/vpn2/VpnUtils.java @@ -20,7 +20,7 @@ import android.net.VpnManager; import android.os.RemoteException; import android.provider.Settings; import android.security.Credentials; -import android.security.KeyStore; +import android.security.LegacyVpnProfileStore; import com.android.internal.net.LegacyVpnInfo; import com.android.internal.net.VpnConfig; @@ -28,27 +28,25 @@ import com.android.internal.net.VpnConfig; /** * Utility functions for vpn. * - * Keystore methods should only be called in system user + * LegacyVpnProfileStore methods should only be called in system user */ public class VpnUtils { private static final String TAG = "VpnUtils"; public static String getLockdownVpn() { - final byte[] value = KeyStore.getInstance().get( - Credentials.LOCKDOWN_VPN, true /* suppressKeyNotFoundWarning */); + final byte[] value = LegacyVpnProfileStore.get(Credentials.LOCKDOWN_VPN); return value == null ? null : new String(value); } public static void clearLockdownVpn(Context context) { - KeyStore.getInstance().delete(Credentials.LOCKDOWN_VPN); + LegacyVpnProfileStore.remove(Credentials.LOCKDOWN_VPN); // Always notify VpnManager after keystore update getVpnManager(context).updateLockdownVpn(); } public static void setLockdownVpn(Context context, String lockdownKey) { - KeyStore.getInstance().put(Credentials.LOCKDOWN_VPN, lockdownKey.getBytes(), - KeyStore.UID_SELF, /* flags */ 0); + LegacyVpnProfileStore.put(Credentials.LOCKDOWN_VPN, lockdownKey.getBytes()); // Always notify VpnManager after keystore update getVpnManager(context).updateLockdownVpn(); }