Loading services/java/com/android/server/wifi/WifiController.java +14 −0 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,7 @@ class WifiController extends StateMachine { private int mStayAwakeConditions; private int mStayAwakeConditions; private long mIdleMillis; private long mIdleMillis; private int mSleepPolicy; private int mSleepPolicy; private boolean mFirstUserSignOnSeen = false; private AlarmManager mAlarmManager; private AlarmManager mAlarmManager; private PendingIntent mIdleIntent; private PendingIntent mIdleIntent; Loading Loading @@ -113,6 +114,7 @@ class WifiController extends StateMachine { static final int CMD_AIRPLANE_TOGGLED = BASE + 9; static final int CMD_AIRPLANE_TOGGLED = BASE + 9; static final int CMD_SET_AP = BASE + 10; static final int CMD_SET_AP = BASE + 10; static final int CMD_DEFERRED_TOGGLE = BASE + 11; static final int CMD_DEFERRED_TOGGLE = BASE + 11; static final int CMD_USER_PRESENT = BASE + 12; private DefaultState mDefaultState = new DefaultState(); private DefaultState mDefaultState = new DefaultState(); private StaEnabledState mStaEnabledState = new StaEnabledState(); private StaEnabledState mStaEnabledState = new StaEnabledState(); Loading Loading @@ -361,6 +363,9 @@ class WifiController extends StateMachine { case CMD_AIRPLANE_TOGGLED: case CMD_AIRPLANE_TOGGLED: case CMD_EMERGENCY_MODE_CHANGED: case CMD_EMERGENCY_MODE_CHANGED: break; break; case CMD_USER_PRESENT: mFirstUserSignOnSeen = true; break; case CMD_DEFERRED_TOGGLE: case CMD_DEFERRED_TOGGLE: log("DEFERRED_TOGGLE ignored due to state change"); log("DEFERRED_TOGGLE ignored due to state change"); break; break; Loading Loading @@ -639,6 +644,15 @@ class WifiController extends StateMachine { if (msg.what == CMD_DEVICE_IDLE) { if (msg.what == CMD_DEVICE_IDLE) { checkLocksAndTransitionWhenDeviceIdle(); checkLocksAndTransitionWhenDeviceIdle(); // We let default state handle the rest of work // We let default state handle the rest of work } else if (msg.what == CMD_USER_PRESENT) { // TLS networks can't connect until user unlocks keystore. KeyStore // unlocks when the user punches PIN after the reboot. So use this // trigger to get those networks connected. if (mFirstUserSignOnSeen == false) { mWifiStateMachine.reloadTlsNetworksAndReconnect(); } mFirstUserSignOnSeen = true; return HANDLED; } } return NOT_HANDLED; return NOT_HANDLED; } } Loading services/java/com/android/server/wifi/WifiService.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -83,6 +83,7 @@ import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGE import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF; import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF; import static com.android.server.wifi.WifiController.CMD_SCREEN_ON; import static com.android.server.wifi.WifiController.CMD_SCREEN_ON; import static com.android.server.wifi.WifiController.CMD_SET_AP; import static com.android.server.wifi.WifiController.CMD_SET_AP; import static com.android.server.wifi.WifiController.CMD_USER_PRESENT; import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED; import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED; /** /** * WifiService handles remote WiFi operation requests by implementing * WifiService handles remote WiFi operation requests by implementing Loading Loading @@ -1084,6 +1085,8 @@ public final class WifiService extends IWifiManager.Stub { String action = intent.getAction(); String action = intent.getAction(); if (action.equals(Intent.ACTION_SCREEN_ON)) { if (action.equals(Intent.ACTION_SCREEN_ON)) { mWifiController.sendMessage(CMD_SCREEN_ON); mWifiController.sendMessage(CMD_SCREEN_ON); } else if (action.equals(Intent.ACTION_USER_PRESENT)) { mWifiController.sendMessage(CMD_USER_PRESENT); } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { mWifiController.sendMessage(CMD_SCREEN_OFF); mWifiController.sendMessage(CMD_SCREEN_OFF); } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { Loading Loading @@ -1120,6 +1123,7 @@ public final class WifiService extends IWifiManager.Stub { private void registerForBroadcasts() { private void registerForBroadcasts() { IntentFilter intentFilter = new IntentFilter(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(Intent.ACTION_USER_PRESENT); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); Loading wifi/java/android/net/wifi/WifiConfigStore.java +22 −1 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.InetAddress; import java.net.UnknownHostException; import java.net.UnknownHostException; import java.security.PublicKey; import java.util.ArrayList; import java.util.ArrayList; import java.util.BitSet; import java.util.BitSet; import java.util.Collection; import java.util.Collection; Loading Loading @@ -742,6 +743,26 @@ class WifiConfigStore { markAllNetworksDisabledExcept(INVALID_NETWORK_ID); markAllNetworksDisabledExcept(INVALID_NETWORK_ID); } } boolean needsUnlockedKeyStore() { // Any network using certificates to authenticate access requires // unlocked key store; unless the certificates can be stored with // hardware encryption for(WifiConfiguration config : mConfiguredNetworks.values()) { if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) && config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { if (config.enterpriseConfig.needsSoftwareBackedKeyStore()) { return true; } } } return false; } private void writeIpAndProxyConfigurations() { private void writeIpAndProxyConfigurations() { /* Make a copy */ /* Make a copy */ Loading Loading @@ -1223,7 +1244,6 @@ class WifiConfigStore { * Keyguard settings may eventually be controlled by device policy. * Keyguard settings may eventually be controlled by device policy. * We check here if keystore is unlocked before installing * We check here if keystore is unlocked before installing * credentials. * credentials. * TODO: Figure a way to store these credentials for wifi alone * TODO: Do we need a dialog here ? * TODO: Do we need a dialog here ? */ */ if (mKeyStore.state() != KeyStore.State.UNLOCKED) { if (mKeyStore.state() != KeyStore.State.UNLOCKED) { Loading Loading @@ -1583,6 +1603,7 @@ class WifiConfigStore { } } config.enterpriseConfig.migrateCerts(mKeyStore); config.enterpriseConfig.migrateCerts(mKeyStore); config.enterpriseConfig.initializeSoftwareKeystoreFlag(mKeyStore); } } private String removeDoubleQuotes(String string) { private String removeDoubleQuotes(String string) { Loading wifi/java/android/net/wifi/WifiEnterpriseConfig.java +93 −3 Original line number Original line Diff line number Diff line Loading @@ -19,8 +19,10 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.Parcelable; import android.os.Process; import android.os.Process; import android.security.Credentials; import android.security.Credentials; import android.security.KeyChain; import android.security.KeyStore; import android.security.KeyStore; import android.text.TextUtils; import android.text.TextUtils; import android.util.Slog; import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.IOException; Loading @@ -43,6 +45,7 @@ import java.util.Map; */ */ public class WifiEnterpriseConfig implements Parcelable { public class WifiEnterpriseConfig implements Parcelable { private static final String TAG = "WifiEnterpriseConfig"; private static final String TAG = "WifiEnterpriseConfig"; private static final boolean DBG = false; /** /** * In old configurations, the "private_key" field was used. However, newer * In old configurations, the "private_key" field was used. However, newer * configurations use the key_id field with the engine_id set to "keystore". * configurations use the key_id field with the engine_id set to "keystore". Loading Loading @@ -91,6 +94,7 @@ public class WifiEnterpriseConfig implements Parcelable { private X509Certificate mCaCert; private X509Certificate mCaCert; private PrivateKey mClientPrivateKey; private PrivateKey mClientPrivateKey; private X509Certificate mClientCertificate; private X509Certificate mClientCertificate; private boolean mNeedsSoftwareKeystore = false; /** This represents an empty value of an enterprise field. /** This represents an empty value of an enterprise field. * NULL is used at wpa_supplicant to indicate an empty value * NULL is used at wpa_supplicant to indicate an empty value Loading Loading @@ -509,6 +513,18 @@ public class WifiEnterpriseConfig implements Parcelable { return true; return true; } } static boolean isHardwareBackedKey(PrivateKey key) { return KeyChain.isBoundKeyAlgorithm(key.getAlgorithm()); } static boolean hasHardwareBackedKey(Certificate certificate) { return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm()); } boolean needsSoftwareBackedKeyStore() { return mNeedsSoftwareKeystore; } boolean installKeys(android.security.KeyStore keyStore, String name) { boolean installKeys(android.security.KeyStore keyStore, String name) { boolean ret = true; boolean ret = true; String privKeyName = Credentials.USER_PRIVATE_KEY + name; String privKeyName = Credentials.USER_PRIVATE_KEY + name; Loading @@ -516,8 +532,23 @@ public class WifiEnterpriseConfig implements Parcelable { String caCertName = Credentials.CA_CERTIFICATE + name; String caCertName = Credentials.CA_CERTIFICATE + name; if (mClientCertificate != null) { if (mClientCertificate != null) { byte[] privKeyData = mClientPrivateKey.getEncoded(); byte[] privKeyData = mClientPrivateKey.getEncoded(); if (isHardwareBackedKey(mClientPrivateKey)) { // Hardware backed key store is secure enough to store keys un-encrypted, this // removes the need for user to punch a PIN to get access to these keys if (DBG) Slog.d(TAG, "importing keys " + name + " in hardware backed " + "store"); ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, KeyStore.FLAG_NONE); } else { // Software backed key store is NOT secure enough to store keys un-encrypted. // Save keys encrypted so they are protected with user's PIN. User will // have to unlock phone before being able to use these keys and connect to // networks. if (DBG) Slog.d(TAG, "importing keys " + name + " in software backed store"); ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED); KeyStore.FLAG_ENCRYPTED); mNeedsSoftwareKeystore = true; } if (ret == false) { if (ret == false) { return ret; return ret; } } Loading Loading @@ -561,7 +592,9 @@ public class WifiEnterpriseConfig implements Parcelable { Certificate cert) { Certificate cert) { try { try { byte[] certData = Credentials.convertToPem(cert); byte[] certData = Credentials.convertToPem(cert); return keyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED); if (DBG) Slog.d(TAG, "putting certificate " + name + " in keystore"); return keyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_NONE); } catch (IOException e1) { } catch (IOException e1) { return false; return false; } catch (CertificateException e2) { } catch (CertificateException e2) { Loading @@ -573,6 +606,7 @@ public class WifiEnterpriseConfig implements Parcelable { String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); // a valid client certificate is configured // a valid client certificate is configured if (!TextUtils.isEmpty(client)) { if (!TextUtils.isEmpty(client)) { if (DBG) Slog.d(TAG, "removing client private key and user cert"); keyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); keyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); keyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); keyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); } } Loading @@ -580,6 +614,7 @@ public class WifiEnterpriseConfig implements Parcelable { String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX); String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX); // a valid ca certificate is configured // a valid ca certificate is configured if (!TextUtils.isEmpty(ca)) { if (!TextUtils.isEmpty(ca)) { if (DBG) Slog.d(TAG, "removing CA cert"); keyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); keyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); } } } } Loading Loading @@ -684,6 +719,61 @@ public class WifiEnterpriseConfig implements Parcelable { } } } } void initializeSoftwareKeystoreFlag(android.security.KeyStore keyStore) { String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); if (!TextUtils.isEmpty(client)) { // a valid client certificate is configured // BUGBUG: keyStore.get() never returns certBytes; because it is not // taking WIFI_UID as a parameter. It always looks for certificate // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that // all certificates need software keystore until we get the get() API // fixed. mNeedsSoftwareKeystore = true; /* try { if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials .USER_CERTIFICATE + client); CertificateFactory factory = CertificateFactory.getInstance("X.509"); if (factory == null) { Slog.e(TAG, "Error getting certificate factory"); return; } byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); if (certBytes != null) { Certificate cert = (X509Certificate) factory.generateCertificate( new ByteArrayInputStream(certBytes)); if (cert != null) { mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials .USER_CERTIFICATE + client); if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : "does not need" ) + " software key store"); } else { Slog.d(TAG, "could not generate certificate"); } } else { Slog.e(TAG, "Could not load client certificate " + Credentials .USER_CERTIFICATE + client); mNeedsSoftwareKeystore = true; } } catch(CertificateException e) { Slog.e(TAG, "Could not read certificates"); mCaCert = null; mClientCertificate = null; } */ } } private String removeDoubleQuotes(String string) { private String removeDoubleQuotes(String string) { if (TextUtils.isEmpty(string)) return ""; if (TextUtils.isEmpty(string)) return ""; int length = string.length(); int length = string.length(); Loading wifi/java/android/net/wifi/WifiStateMachine.java +18 −0 Original line number Original line Diff line number Diff line Loading @@ -426,6 +426,8 @@ public class WifiStateMachine extends StateMachine { static final int CMD_IP_ADDRESS_UPDATED = BASE + 140; static final int CMD_IP_ADDRESS_UPDATED = BASE + 140; /* An IP address was removed from our interface */ /* An IP address was removed from our interface */ static final int CMD_IP_ADDRESS_REMOVED = BASE + 141; static final int CMD_IP_ADDRESS_REMOVED = BASE + 141; /* Reload all networks and reconnect */ static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142; /* Wifi state machine modes of operation */ /* Wifi state machine modes of operation */ /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ Loading Loading @@ -1319,6 +1321,14 @@ public class WifiStateMachine extends StateMachine { sendMessage(CMD_REASSOCIATE); sendMessage(CMD_REASSOCIATE); } } /** * Reload networks and then reconnect; helps load correct data for TLS networks */ public void reloadTlsNetworksAndReconnect() { sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); } /** /** * Add a network synchronously * Add a network synchronously * * Loading Loading @@ -2445,6 +2455,7 @@ public class WifiStateMachine extends StateMachine { case CMD_DISCONNECT: case CMD_DISCONNECT: case CMD_RECONNECT: case CMD_RECONNECT: case CMD_REASSOCIATE: case CMD_REASSOCIATE: case CMD_RELOAD_TLS_AND_RECONNECT: case WifiMonitor.SUP_CONNECTION_EVENT: case WifiMonitor.SUP_CONNECTION_EVENT: case WifiMonitor.SUP_DISCONNECTION_EVENT: case WifiMonitor.SUP_DISCONNECTION_EVENT: case WifiMonitor.NETWORK_CONNECTION_EVENT: case WifiMonitor.NETWORK_CONNECTION_EVENT: Loading Loading @@ -3395,6 +3406,13 @@ public class WifiStateMachine extends StateMachine { case CMD_REASSOCIATE: case CMD_REASSOCIATE: mWifiNative.reassociate(); mWifiNative.reassociate(); break; break; case CMD_RELOAD_TLS_AND_RECONNECT: if (mWifiConfigStore.needsUnlockedKeyStore()) { logd("Reconnecting to give a chance to un-connected TLS networks"); mWifiNative.disconnect(); mWifiNative.reconnect(); } break; case WifiManager.CONNECT_NETWORK: case WifiManager.CONNECT_NETWORK: /* The connect message can contain a network id passed as arg1 on message or /* The connect message can contain a network id passed as arg1 on message or * or a config passed as obj on message. * or a config passed as obj on message. Loading Loading
services/java/com/android/server/wifi/WifiController.java +14 −0 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,7 @@ class WifiController extends StateMachine { private int mStayAwakeConditions; private int mStayAwakeConditions; private long mIdleMillis; private long mIdleMillis; private int mSleepPolicy; private int mSleepPolicy; private boolean mFirstUserSignOnSeen = false; private AlarmManager mAlarmManager; private AlarmManager mAlarmManager; private PendingIntent mIdleIntent; private PendingIntent mIdleIntent; Loading Loading @@ -113,6 +114,7 @@ class WifiController extends StateMachine { static final int CMD_AIRPLANE_TOGGLED = BASE + 9; static final int CMD_AIRPLANE_TOGGLED = BASE + 9; static final int CMD_SET_AP = BASE + 10; static final int CMD_SET_AP = BASE + 10; static final int CMD_DEFERRED_TOGGLE = BASE + 11; static final int CMD_DEFERRED_TOGGLE = BASE + 11; static final int CMD_USER_PRESENT = BASE + 12; private DefaultState mDefaultState = new DefaultState(); private DefaultState mDefaultState = new DefaultState(); private StaEnabledState mStaEnabledState = new StaEnabledState(); private StaEnabledState mStaEnabledState = new StaEnabledState(); Loading Loading @@ -361,6 +363,9 @@ class WifiController extends StateMachine { case CMD_AIRPLANE_TOGGLED: case CMD_AIRPLANE_TOGGLED: case CMD_EMERGENCY_MODE_CHANGED: case CMD_EMERGENCY_MODE_CHANGED: break; break; case CMD_USER_PRESENT: mFirstUserSignOnSeen = true; break; case CMD_DEFERRED_TOGGLE: case CMD_DEFERRED_TOGGLE: log("DEFERRED_TOGGLE ignored due to state change"); log("DEFERRED_TOGGLE ignored due to state change"); break; break; Loading Loading @@ -639,6 +644,15 @@ class WifiController extends StateMachine { if (msg.what == CMD_DEVICE_IDLE) { if (msg.what == CMD_DEVICE_IDLE) { checkLocksAndTransitionWhenDeviceIdle(); checkLocksAndTransitionWhenDeviceIdle(); // We let default state handle the rest of work // We let default state handle the rest of work } else if (msg.what == CMD_USER_PRESENT) { // TLS networks can't connect until user unlocks keystore. KeyStore // unlocks when the user punches PIN after the reboot. So use this // trigger to get those networks connected. if (mFirstUserSignOnSeen == false) { mWifiStateMachine.reloadTlsNetworksAndReconnect(); } mFirstUserSignOnSeen = true; return HANDLED; } } return NOT_HANDLED; return NOT_HANDLED; } } Loading
services/java/com/android/server/wifi/WifiService.java +4 −0 Original line number Original line Diff line number Diff line Loading @@ -83,6 +83,7 @@ import static com.android.server.wifi.WifiController.CMD_SCAN_ALWAYS_MODE_CHANGE import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF; import static com.android.server.wifi.WifiController.CMD_SCREEN_OFF; import static com.android.server.wifi.WifiController.CMD_SCREEN_ON; import static com.android.server.wifi.WifiController.CMD_SCREEN_ON; import static com.android.server.wifi.WifiController.CMD_SET_AP; import static com.android.server.wifi.WifiController.CMD_SET_AP; import static com.android.server.wifi.WifiController.CMD_USER_PRESENT; import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED; import static com.android.server.wifi.WifiController.CMD_WIFI_TOGGLED; /** /** * WifiService handles remote WiFi operation requests by implementing * WifiService handles remote WiFi operation requests by implementing Loading Loading @@ -1084,6 +1085,8 @@ public final class WifiService extends IWifiManager.Stub { String action = intent.getAction(); String action = intent.getAction(); if (action.equals(Intent.ACTION_SCREEN_ON)) { if (action.equals(Intent.ACTION_SCREEN_ON)) { mWifiController.sendMessage(CMD_SCREEN_ON); mWifiController.sendMessage(CMD_SCREEN_ON); } else if (action.equals(Intent.ACTION_USER_PRESENT)) { mWifiController.sendMessage(CMD_USER_PRESENT); } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { } else if (action.equals(Intent.ACTION_SCREEN_OFF)) { mWifiController.sendMessage(CMD_SCREEN_OFF); mWifiController.sendMessage(CMD_SCREEN_OFF); } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { } else if (action.equals(Intent.ACTION_BATTERY_CHANGED)) { Loading Loading @@ -1120,6 +1123,7 @@ public final class WifiService extends IWifiManager.Stub { private void registerForBroadcasts() { private void registerForBroadcasts() { IntentFilter intentFilter = new IntentFilter(); IntentFilter intentFilter = new IntentFilter(); intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(Intent.ACTION_SCREEN_ON); intentFilter.addAction(Intent.ACTION_USER_PRESENT); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); intentFilter.addAction(Intent.ACTION_SCREEN_OFF); intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); intentFilter.addAction(Intent.ACTION_BATTERY_CHANGED); intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); intentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); Loading
wifi/java/android/net/wifi/WifiConfigStore.java +22 −1 Original line number Original line Diff line number Diff line Loading @@ -57,6 +57,7 @@ import java.io.IOException; import java.io.PrintWriter; import java.io.PrintWriter; import java.net.InetAddress; import java.net.InetAddress; import java.net.UnknownHostException; import java.net.UnknownHostException; import java.security.PublicKey; import java.util.ArrayList; import java.util.ArrayList; import java.util.BitSet; import java.util.BitSet; import java.util.Collection; import java.util.Collection; Loading Loading @@ -742,6 +743,26 @@ class WifiConfigStore { markAllNetworksDisabledExcept(INVALID_NETWORK_ID); markAllNetworksDisabledExcept(INVALID_NETWORK_ID); } } boolean needsUnlockedKeyStore() { // Any network using certificates to authenticate access requires // unlocked key store; unless the certificates can be stored with // hardware encryption for(WifiConfiguration config : mConfiguredNetworks.values()) { if (config.allowedKeyManagement.get(KeyMgmt.WPA_EAP) && config.allowedKeyManagement.get(KeyMgmt.IEEE8021X)) { if (config.enterpriseConfig.needsSoftwareBackedKeyStore()) { return true; } } } return false; } private void writeIpAndProxyConfigurations() { private void writeIpAndProxyConfigurations() { /* Make a copy */ /* Make a copy */ Loading Loading @@ -1223,7 +1244,6 @@ class WifiConfigStore { * Keyguard settings may eventually be controlled by device policy. * Keyguard settings may eventually be controlled by device policy. * We check here if keystore is unlocked before installing * We check here if keystore is unlocked before installing * credentials. * credentials. * TODO: Figure a way to store these credentials for wifi alone * TODO: Do we need a dialog here ? * TODO: Do we need a dialog here ? */ */ if (mKeyStore.state() != KeyStore.State.UNLOCKED) { if (mKeyStore.state() != KeyStore.State.UNLOCKED) { Loading Loading @@ -1583,6 +1603,7 @@ class WifiConfigStore { } } config.enterpriseConfig.migrateCerts(mKeyStore); config.enterpriseConfig.migrateCerts(mKeyStore); config.enterpriseConfig.initializeSoftwareKeystoreFlag(mKeyStore); } } private String removeDoubleQuotes(String string) { private String removeDoubleQuotes(String string) { Loading
wifi/java/android/net/wifi/WifiEnterpriseConfig.java +93 −3 Original line number Original line Diff line number Diff line Loading @@ -19,8 +19,10 @@ import android.os.Parcel; import android.os.Parcelable; import android.os.Parcelable; import android.os.Process; import android.os.Process; import android.security.Credentials; import android.security.Credentials; import android.security.KeyChain; import android.security.KeyStore; import android.security.KeyStore; import android.text.TextUtils; import android.text.TextUtils; import android.util.Slog; import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.IOException; Loading @@ -43,6 +45,7 @@ import java.util.Map; */ */ public class WifiEnterpriseConfig implements Parcelable { public class WifiEnterpriseConfig implements Parcelable { private static final String TAG = "WifiEnterpriseConfig"; private static final String TAG = "WifiEnterpriseConfig"; private static final boolean DBG = false; /** /** * In old configurations, the "private_key" field was used. However, newer * In old configurations, the "private_key" field was used. However, newer * configurations use the key_id field with the engine_id set to "keystore". * configurations use the key_id field with the engine_id set to "keystore". Loading Loading @@ -91,6 +94,7 @@ public class WifiEnterpriseConfig implements Parcelable { private X509Certificate mCaCert; private X509Certificate mCaCert; private PrivateKey mClientPrivateKey; private PrivateKey mClientPrivateKey; private X509Certificate mClientCertificate; private X509Certificate mClientCertificate; private boolean mNeedsSoftwareKeystore = false; /** This represents an empty value of an enterprise field. /** This represents an empty value of an enterprise field. * NULL is used at wpa_supplicant to indicate an empty value * NULL is used at wpa_supplicant to indicate an empty value Loading Loading @@ -509,6 +513,18 @@ public class WifiEnterpriseConfig implements Parcelable { return true; return true; } } static boolean isHardwareBackedKey(PrivateKey key) { return KeyChain.isBoundKeyAlgorithm(key.getAlgorithm()); } static boolean hasHardwareBackedKey(Certificate certificate) { return KeyChain.isBoundKeyAlgorithm(certificate.getPublicKey().getAlgorithm()); } boolean needsSoftwareBackedKeyStore() { return mNeedsSoftwareKeystore; } boolean installKeys(android.security.KeyStore keyStore, String name) { boolean installKeys(android.security.KeyStore keyStore, String name) { boolean ret = true; boolean ret = true; String privKeyName = Credentials.USER_PRIVATE_KEY + name; String privKeyName = Credentials.USER_PRIVATE_KEY + name; Loading @@ -516,8 +532,23 @@ public class WifiEnterpriseConfig implements Parcelable { String caCertName = Credentials.CA_CERTIFICATE + name; String caCertName = Credentials.CA_CERTIFICATE + name; if (mClientCertificate != null) { if (mClientCertificate != null) { byte[] privKeyData = mClientPrivateKey.getEncoded(); byte[] privKeyData = mClientPrivateKey.getEncoded(); if (isHardwareBackedKey(mClientPrivateKey)) { // Hardware backed key store is secure enough to store keys un-encrypted, this // removes the need for user to punch a PIN to get access to these keys if (DBG) Slog.d(TAG, "importing keys " + name + " in hardware backed " + "store"); ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, KeyStore.FLAG_NONE); } else { // Software backed key store is NOT secure enough to store keys un-encrypted. // Save keys encrypted so they are protected with user's PIN. User will // have to unlock phone before being able to use these keys and connect to // networks. if (DBG) Slog.d(TAG, "importing keys " + name + " in software backed store"); ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED); KeyStore.FLAG_ENCRYPTED); mNeedsSoftwareKeystore = true; } if (ret == false) { if (ret == false) { return ret; return ret; } } Loading Loading @@ -561,7 +592,9 @@ public class WifiEnterpriseConfig implements Parcelable { Certificate cert) { Certificate cert) { try { try { byte[] certData = Credentials.convertToPem(cert); byte[] certData = Credentials.convertToPem(cert); return keyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_ENCRYPTED); if (DBG) Slog.d(TAG, "putting certificate " + name + " in keystore"); return keyStore.put(name, certData, Process.WIFI_UID, KeyStore.FLAG_NONE); } catch (IOException e1) { } catch (IOException e1) { return false; return false; } catch (CertificateException e2) { } catch (CertificateException e2) { Loading @@ -573,6 +606,7 @@ public class WifiEnterpriseConfig implements Parcelable { String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); // a valid client certificate is configured // a valid client certificate is configured if (!TextUtils.isEmpty(client)) { if (!TextUtils.isEmpty(client)) { if (DBG) Slog.d(TAG, "removing client private key and user cert"); keyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); keyStore.delKey(Credentials.USER_PRIVATE_KEY + client, Process.WIFI_UID); keyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); keyStore.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID); } } Loading @@ -580,6 +614,7 @@ public class WifiEnterpriseConfig implements Parcelable { String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX); String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX); // a valid ca certificate is configured // a valid ca certificate is configured if (!TextUtils.isEmpty(ca)) { if (!TextUtils.isEmpty(ca)) { if (DBG) Slog.d(TAG, "removing CA cert"); keyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); keyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID); } } } } Loading Loading @@ -684,6 +719,61 @@ public class WifiEnterpriseConfig implements Parcelable { } } } } void initializeSoftwareKeystoreFlag(android.security.KeyStore keyStore) { String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX); if (!TextUtils.isEmpty(client)) { // a valid client certificate is configured // BUGBUG: keyStore.get() never returns certBytes; because it is not // taking WIFI_UID as a parameter. It always looks for certificate // with SYSTEM_UID, and never finds any Wifi certificates. Assuming that // all certificates need software keystore until we get the get() API // fixed. mNeedsSoftwareKeystore = true; /* try { if (DBG) Slog.d(TAG, "Loading client certificate " + Credentials .USER_CERTIFICATE + client); CertificateFactory factory = CertificateFactory.getInstance("X.509"); if (factory == null) { Slog.e(TAG, "Error getting certificate factory"); return; } byte[] certBytes = keyStore.get(Credentials.USER_CERTIFICATE + client); if (certBytes != null) { Certificate cert = (X509Certificate) factory.generateCertificate( new ByteArrayInputStream(certBytes)); if (cert != null) { mNeedsSoftwareKeystore = hasHardwareBackedKey(cert); if (DBG) Slog.d(TAG, "Loaded client certificate " + Credentials .USER_CERTIFICATE + client); if (DBG) Slog.d(TAG, "It " + (mNeedsSoftwareKeystore ? "needs" : "does not need" ) + " software key store"); } else { Slog.d(TAG, "could not generate certificate"); } } else { Slog.e(TAG, "Could not load client certificate " + Credentials .USER_CERTIFICATE + client); mNeedsSoftwareKeystore = true; } } catch(CertificateException e) { Slog.e(TAG, "Could not read certificates"); mCaCert = null; mClientCertificate = null; } */ } } private String removeDoubleQuotes(String string) { private String removeDoubleQuotes(String string) { if (TextUtils.isEmpty(string)) return ""; if (TextUtils.isEmpty(string)) return ""; int length = string.length(); int length = string.length(); Loading
wifi/java/android/net/wifi/WifiStateMachine.java +18 −0 Original line number Original line Diff line number Diff line Loading @@ -426,6 +426,8 @@ public class WifiStateMachine extends StateMachine { static final int CMD_IP_ADDRESS_UPDATED = BASE + 140; static final int CMD_IP_ADDRESS_UPDATED = BASE + 140; /* An IP address was removed from our interface */ /* An IP address was removed from our interface */ static final int CMD_IP_ADDRESS_REMOVED = BASE + 141; static final int CMD_IP_ADDRESS_REMOVED = BASE + 141; /* Reload all networks and reconnect */ static final int CMD_RELOAD_TLS_AND_RECONNECT = BASE + 142; /* Wifi state machine modes of operation */ /* Wifi state machine modes of operation */ /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ /* CONNECT_MODE - connect to any 'known' AP when it becomes available */ Loading Loading @@ -1319,6 +1321,14 @@ public class WifiStateMachine extends StateMachine { sendMessage(CMD_REASSOCIATE); sendMessage(CMD_REASSOCIATE); } } /** * Reload networks and then reconnect; helps load correct data for TLS networks */ public void reloadTlsNetworksAndReconnect() { sendMessage(CMD_RELOAD_TLS_AND_RECONNECT); } /** /** * Add a network synchronously * Add a network synchronously * * Loading Loading @@ -2445,6 +2455,7 @@ public class WifiStateMachine extends StateMachine { case CMD_DISCONNECT: case CMD_DISCONNECT: case CMD_RECONNECT: case CMD_RECONNECT: case CMD_REASSOCIATE: case CMD_REASSOCIATE: case CMD_RELOAD_TLS_AND_RECONNECT: case WifiMonitor.SUP_CONNECTION_EVENT: case WifiMonitor.SUP_CONNECTION_EVENT: case WifiMonitor.SUP_DISCONNECTION_EVENT: case WifiMonitor.SUP_DISCONNECTION_EVENT: case WifiMonitor.NETWORK_CONNECTION_EVENT: case WifiMonitor.NETWORK_CONNECTION_EVENT: Loading Loading @@ -3395,6 +3406,13 @@ public class WifiStateMachine extends StateMachine { case CMD_REASSOCIATE: case CMD_REASSOCIATE: mWifiNative.reassociate(); mWifiNative.reassociate(); break; break; case CMD_RELOAD_TLS_AND_RECONNECT: if (mWifiConfigStore.needsUnlockedKeyStore()) { logd("Reconnecting to give a chance to un-connected TLS networks"); mWifiNative.disconnect(); mWifiNative.reconnect(); } break; case WifiManager.CONNECT_NETWORK: case WifiManager.CONNECT_NETWORK: /* The connect message can contain a network id passed as arg1 on message or /* The connect message can contain a network id passed as arg1 on message or * or a config passed as obj on message. * or a config passed as obj on message. Loading