Merge "Keystore 2.0: Make Legacy VPN settings ready for Keystore 2.0" am: 3c7b085331
am: bae6535b75
Original change: https://android-review.googlesource.com/c/platform/packages/apps/Settings/+/1569702 MUST ONLY BE SUBMITTED BY AUTOMERGER Change-Id: I4395ebf453fd712d9870580a90c370b42a770d7a
This commit is contained in:
@@ -28,6 +28,7 @@ import java.security.KeyStoreException;
|
|||||||
import java.security.NoSuchAlgorithmException;
|
import java.security.NoSuchAlgorithmException;
|
||||||
import java.security.PrivateKey;
|
import java.security.PrivateKey;
|
||||||
import java.security.UnrecoverableKeyException;
|
import java.security.UnrecoverableKeyException;
|
||||||
|
import java.security.cert.Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Enumeration;
|
import java.util.Enumeration;
|
||||||
@@ -88,6 +89,10 @@ public class AndroidKeystoreAliasLoader {
|
|||||||
if (key != null) {
|
if (key != null) {
|
||||||
if (key instanceof PrivateKey) {
|
if (key instanceof PrivateKey) {
|
||||||
mKeyCertAliases.add(alias);
|
mKeyCertAliases.add(alias);
|
||||||
|
final Certificate[] cert = keyStore.getCertificateChain(alias);
|
||||||
|
if (cert != null && cert.length >= 2) {
|
||||||
|
mCaCertAliases.add(alias);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (keyStore.getCertificate(alias) != null) {
|
if (keyStore.getCertificate(alias) != null) {
|
||||||
|
@@ -24,8 +24,6 @@ import android.content.pm.PackageManager;
|
|||||||
import android.net.ProxyInfo;
|
import android.net.ProxyInfo;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.SystemProperties;
|
import android.os.SystemProperties;
|
||||||
import android.security.Credentials;
|
|
||||||
import android.security.KeyStore;
|
|
||||||
import android.text.Editable;
|
import android.text.Editable;
|
||||||
import android.text.TextWatcher;
|
import android.text.TextWatcher;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -42,10 +40,12 @@ import androidx.appcompat.app.AlertDialog;
|
|||||||
import com.android.internal.net.VpnProfile;
|
import com.android.internal.net.VpnProfile;
|
||||||
import com.android.net.module.util.ProxyUtils;
|
import com.android.net.module.util.ProxyUtils;
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
|
import com.android.settings.utils.AndroidKeystoreAliasLoader;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,7 +58,7 @@ import java.util.List;
|
|||||||
class ConfigDialog extends AlertDialog implements TextWatcher,
|
class ConfigDialog extends AlertDialog implements TextWatcher,
|
||||||
View.OnClickListener, AdapterView.OnItemSelectedListener,
|
View.OnClickListener, AdapterView.OnItemSelectedListener,
|
||||||
CompoundButton.OnCheckedChangeListener {
|
CompoundButton.OnCheckedChangeListener {
|
||||||
private final KeyStore mKeyStore = KeyStore.getInstance();
|
private static final String TAG = "ConfigDialog";
|
||||||
private final DialogInterface.OnClickListener mListener;
|
private final DialogInterface.OnClickListener mListener;
|
||||||
private final VpnProfile mProfile;
|
private final VpnProfile mProfile;
|
||||||
|
|
||||||
@@ -153,10 +153,13 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
|
|||||||
mL2tpSecret.setTextAppearance(android.R.style.TextAppearance_DeviceDefault_Medium);
|
mL2tpSecret.setTextAppearance(android.R.style.TextAppearance_DeviceDefault_Medium);
|
||||||
mIpsecIdentifier.setText(mProfile.ipsecIdentifier);
|
mIpsecIdentifier.setText(mProfile.ipsecIdentifier);
|
||||||
mIpsecSecret.setText(mProfile.ipsecSecret);
|
mIpsecSecret.setText(mProfile.ipsecSecret);
|
||||||
loadCertificates(mIpsecUserCert, Credentials.USER_PRIVATE_KEY, 0, mProfile.ipsecUserCert);
|
AndroidKeystoreAliasLoader androidKeystoreAliasLoader =
|
||||||
loadCertificates(mIpsecCaCert, Credentials.CA_CERTIFICATE,
|
new AndroidKeystoreAliasLoader(null);
|
||||||
|
loadCertificates(mIpsecUserCert, androidKeystoreAliasLoader.getKeyCertAliases(), 0,
|
||||||
|
mProfile.ipsecUserCert);
|
||||||
|
loadCertificates(mIpsecCaCert, androidKeystoreAliasLoader.getCaCertAliases(),
|
||||||
R.string.vpn_no_ca_cert, mProfile.ipsecCaCert);
|
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);
|
R.string.vpn_no_server_cert, mProfile.ipsecServerCert);
|
||||||
mSaveLogin.setChecked(mProfile.saveLogin);
|
mSaveLogin.setChecked(mProfile.saveLogin);
|
||||||
mAlwaysOnVpn.setChecked(mProfile.key.equals(VpnUtils.getLockdownVpn()));
|
mAlwaysOnVpn.setChecked(mProfile.key.equals(VpnUtils.getLockdownVpn()));
|
||||||
@@ -511,27 +514,30 @@ class ConfigDialog extends AlertDialog implements TextWatcher,
|
|||||||
typeSpinner.setAdapter(adapter);
|
typeSpinner.setAdapter(adapter);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loadCertificates(Spinner spinner, String prefix, int firstId, String selected) {
|
private void loadCertificates(Spinner spinner, Collection<String> choices, int firstId,
|
||||||
|
String selected) {
|
||||||
Context context = getContext();
|
Context context = getContext();
|
||||||
String first = (firstId == 0) ? "" : context.getString(firstId);
|
String first = (firstId == 0) ? "" : context.getString(firstId);
|
||||||
String[] certificates = mKeyStore.list(prefix);
|
String[] myChoices;
|
||||||
|
|
||||||
if (certificates == null || certificates.length == 0) {
|
if (choices == null || choices.size() == 0) {
|
||||||
certificates = new String[] {first};
|
myChoices = new String[] {first};
|
||||||
} else {
|
} else {
|
||||||
String[] array = new String[certificates.length + 1];
|
myChoices = new String[choices.size() + 1];
|
||||||
array[0] = first;
|
myChoices[0] = first;
|
||||||
System.arraycopy(certificates, 0, array, 1, certificates.length);
|
int i = 1;
|
||||||
certificates = array;
|
for (String c : choices) {
|
||||||
|
myChoices[i++] = c;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
|
ArrayAdapter<String> adapter = new ArrayAdapter<String>(
|
||||||
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);
|
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
spinner.setAdapter(adapter);
|
spinner.setAdapter(adapter);
|
||||||
|
|
||||||
for (int i = 1; i < certificates.length; ++i) {
|
for (int i = 1; i < myChoices.length; ++i) {
|
||||||
if (certificates[i].equals(selected)) {
|
if (myChoices[i].equals(selected)) {
|
||||||
spinner.setSelection(i);
|
spinner.setSelection(i);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ import android.os.Bundle;
|
|||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.security.Credentials;
|
import android.security.Credentials;
|
||||||
import android.security.KeyStore;
|
import android.security.LegacyVpnProfileStore;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
@@ -151,9 +151,8 @@ public class ConfigDialogFragment extends InstrumentedDialogFragment implements
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delete from KeyStore
|
// Delete from profile store.
|
||||||
KeyStore keyStore = KeyStore.getInstance();
|
LegacyVpnProfileStore.remove(Credentials.VPN + profile.key);
|
||||||
keyStore.delete(Credentials.VPN + profile.key, KeyStore.UID_SELF);
|
|
||||||
|
|
||||||
updateLockdownVpn(false, profile);
|
updateLockdownVpn(false, profile);
|
||||||
}
|
}
|
||||||
@@ -188,8 +187,7 @@ public class ConfigDialogFragment extends InstrumentedDialogFragment implements
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void save(VpnProfile profile, boolean lockdown) {
|
private void save(VpnProfile profile, boolean lockdown) {
|
||||||
KeyStore.getInstance().put(Credentials.VPN + profile.key, profile.encode(),
|
LegacyVpnProfileStore.put(Credentials.VPN + profile.key, profile.encode());
|
||||||
KeyStore.UID_SELF, /* flags */ 0);
|
|
||||||
|
|
||||||
// Flush out old version of profile
|
// Flush out old version of profile
|
||||||
disconnect(profile);
|
disconnect(profile);
|
||||||
|
@@ -41,7 +41,7 @@ import android.os.Message;
|
|||||||
import android.os.UserHandle;
|
import android.os.UserHandle;
|
||||||
import android.os.UserManager;
|
import android.os.UserManager;
|
||||||
import android.security.Credentials;
|
import android.security.Credentials;
|
||||||
import android.security.KeyStore;
|
import android.security.LegacyVpnProfileStore;
|
||||||
import android.util.ArrayMap;
|
import android.util.ArrayMap;
|
||||||
import android.util.ArraySet;
|
import android.util.ArraySet;
|
||||||
import android.util.Log;
|
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.LegacyVpnInfo;
|
||||||
import com.android.internal.net.VpnConfig;
|
import com.android.internal.net.VpnConfig;
|
||||||
import com.android.internal.net.VpnProfile;
|
import com.android.internal.net.VpnProfile;
|
||||||
import com.android.internal.util.ArrayUtils;
|
|
||||||
import com.android.settings.R;
|
import com.android.settings.R;
|
||||||
import com.android.settings.RestrictedSettingsFragment;
|
import com.android.settings.RestrictedSettingsFragment;
|
||||||
import com.android.settings.widget.GearPreference;
|
import com.android.settings.widget.GearPreference;
|
||||||
@@ -94,8 +93,6 @@ public class VpnSettings extends RestrictedSettingsFragment implements
|
|||||||
private UserManager mUserManager;
|
private UserManager mUserManager;
|
||||||
private VpnManager mVpnManager;
|
private VpnManager mVpnManager;
|
||||||
|
|
||||||
private final KeyStore mKeyStore = KeyStore.getInstance();
|
|
||||||
|
|
||||||
private Map<String, LegacyVpnPreference> mLegacyVpnPreferences = new ArrayMap<>();
|
private Map<String, LegacyVpnPreference> mLegacyVpnPreferences = new ArrayMap<>();
|
||||||
private Map<AppVpnInfo, AppPreference> mAppPreferences = new ArrayMap<>();
|
private Map<AppVpnInfo, AppPreference> mAppPreferences = new ArrayMap<>();
|
||||||
|
|
||||||
@@ -222,7 +219,7 @@ public class VpnSettings extends RestrictedSettingsFragment implements
|
|||||||
final Context context = activity.getApplicationContext();
|
final Context context = activity.getApplicationContext();
|
||||||
|
|
||||||
// Run heavy RPCs before switching to UI thread
|
// Run heavy RPCs before switching to UI thread
|
||||||
final List<VpnProfile> vpnProfiles = loadVpnProfiles(mKeyStore);
|
final List<VpnProfile> vpnProfiles = loadVpnProfiles();
|
||||||
final List<AppVpnInfo> vpnApps = getVpnApps(context, /* includeProfiles */ true);
|
final List<AppVpnInfo> vpnApps = getVpnApps(context, /* includeProfiles */ true);
|
||||||
|
|
||||||
final Map<String, LegacyVpnInfo> connectedLegacyVpns = getConnectedLegacyVpns();
|
final Map<String, LegacyVpnInfo> connectedLegacyVpns = getConnectedLegacyVpns();
|
||||||
@@ -540,12 +537,13 @@ public class VpnSettings extends RestrictedSettingsFragment implements
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<VpnProfile> loadVpnProfiles(KeyStore keyStore, int... excludeTypes) {
|
private static List<VpnProfile> loadVpnProfiles() {
|
||||||
final ArrayList<VpnProfile> result = Lists.newArrayList();
|
final ArrayList<VpnProfile> result = Lists.newArrayList();
|
||||||
|
|
||||||
for (String key : keyStore.list(Credentials.VPN)) {
|
for (String key : LegacyVpnProfileStore.list(Credentials.VPN)) {
|
||||||
final VpnProfile profile = VpnProfile.decode(key, keyStore.get(Credentials.VPN + key));
|
final VpnProfile profile = VpnProfile.decode(key,
|
||||||
if (profile != null && !ArrayUtils.contains(excludeTypes, profile.type)) {
|
LegacyVpnProfileStore.get(Credentials.VPN + key));
|
||||||
|
if (profile != null) {
|
||||||
result.add(profile);
|
result.add(profile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -20,7 +20,7 @@ import android.net.VpnManager;
|
|||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.provider.Settings;
|
import android.provider.Settings;
|
||||||
import android.security.Credentials;
|
import android.security.Credentials;
|
||||||
import android.security.KeyStore;
|
import android.security.LegacyVpnProfileStore;
|
||||||
|
|
||||||
import com.android.internal.net.LegacyVpnInfo;
|
import com.android.internal.net.LegacyVpnInfo;
|
||||||
import com.android.internal.net.VpnConfig;
|
import com.android.internal.net.VpnConfig;
|
||||||
@@ -28,27 +28,25 @@ import com.android.internal.net.VpnConfig;
|
|||||||
/**
|
/**
|
||||||
* Utility functions for vpn.
|
* 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 {
|
public class VpnUtils {
|
||||||
|
|
||||||
private static final String TAG = "VpnUtils";
|
private static final String TAG = "VpnUtils";
|
||||||
|
|
||||||
public static String getLockdownVpn() {
|
public static String getLockdownVpn() {
|
||||||
final byte[] value = KeyStore.getInstance().get(
|
final byte[] value = LegacyVpnProfileStore.get(Credentials.LOCKDOWN_VPN);
|
||||||
Credentials.LOCKDOWN_VPN, true /* suppressKeyNotFoundWarning */);
|
|
||||||
return value == null ? null : new String(value);
|
return value == null ? null : new String(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void clearLockdownVpn(Context context) {
|
public static void clearLockdownVpn(Context context) {
|
||||||
KeyStore.getInstance().delete(Credentials.LOCKDOWN_VPN);
|
LegacyVpnProfileStore.remove(Credentials.LOCKDOWN_VPN);
|
||||||
// Always notify VpnManager after keystore update
|
// Always notify VpnManager after keystore update
|
||||||
getVpnManager(context).updateLockdownVpn();
|
getVpnManager(context).updateLockdownVpn();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void setLockdownVpn(Context context, String lockdownKey) {
|
public static void setLockdownVpn(Context context, String lockdownKey) {
|
||||||
KeyStore.getInstance().put(Credentials.LOCKDOWN_VPN, lockdownKey.getBytes(),
|
LegacyVpnProfileStore.put(Credentials.LOCKDOWN_VPN, lockdownKey.getBytes());
|
||||||
KeyStore.UID_SELF, /* flags */ 0);
|
|
||||||
// Always notify VpnManager after keystore update
|
// Always notify VpnManager after keystore update
|
||||||
getVpnManager(context).updateLockdownVpn();
|
getVpnManager(context).updateLockdownVpn();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user