summaryrefslogtreecommitdiffstats
path: root/wifi/java/android/net
diff options
context:
space:
mode:
authorVinit Deshapnde <vinitd@google.com>2013-10-04 11:08:06 -0700
committerAndroid Git Automerger <android-git-automerger@android.com>2013-10-04 11:08:06 -0700
commit1e9863f06ad4d006abb0a76677c246d1420d5352 (patch)
treefaeee12dd245f74b6e352c1a69ff4b8b7249f393 /wifi/java/android/net
parent1ff5ad874ef8ad9e9e02cddfe35f793d0c15c47b (diff)
parent90a5192cd4af89a1b363ca25be2a63d0e57010d4 (diff)
downloadframeworks_base-1e9863f06ad4d006abb0a76677c246d1420d5352.zip
frameworks_base-1e9863f06ad4d006abb0a76677c246d1420d5352.tar.gz
frameworks_base-1e9863f06ad4d006abb0a76677c246d1420d5352.tar.bz2
am 90a5192c: am e72aa641: am 3eb6e4b4: Merge "Fix EAP-TLS reconnect after reboot issue" into klp-dev
* commit '90a5192cd4af89a1b363ca25be2a63d0e57010d4': Fix EAP-TLS reconnect after reboot issue
Diffstat (limited to 'wifi/java/android/net')
-rw-r--r--wifi/java/android/net/wifi/WifiConfigStore.java23
-rw-r--r--wifi/java/android/net/wifi/WifiEnterpriseConfig.java96
-rw-r--r--wifi/java/android/net/wifi/WifiStateMachine.java18
3 files changed, 133 insertions, 4 deletions
diff --git a/wifi/java/android/net/wifi/WifiConfigStore.java b/wifi/java/android/net/wifi/WifiConfigStore.java
index f79a4a6..a6ae215 100644
--- a/wifi/java/android/net/wifi/WifiConfigStore.java
+++ b/wifi/java/android/net/wifi/WifiConfigStore.java
@@ -57,6 +57,7 @@ import java.io.IOException;
import java.io.PrintWriter;
import java.net.InetAddress;
import java.net.UnknownHostException;
+import java.security.PublicKey;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.Collection;
@@ -742,6 +743,26 @@ class WifiConfigStore {
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() {
/* Make a copy */
@@ -1223,7 +1244,6 @@ class WifiConfigStore {
* Keyguard settings may eventually be controlled by device policy.
* We check here if keystore is unlocked before installing
* credentials.
- * TODO: Figure a way to store these credentials for wifi alone
* TODO: Do we need a dialog here ?
*/
if (mKeyStore.state() != KeyStore.State.UNLOCKED) {
@@ -1583,6 +1603,7 @@ class WifiConfigStore {
}
config.enterpriseConfig.migrateCerts(mKeyStore);
+ config.enterpriseConfig.initializeSoftwareKeystoreFlag(mKeyStore);
}
private String removeDoubleQuotes(String string) {
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index e357804..c7ebecb 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -19,8 +19,10 @@ import android.os.Parcel;
import android.os.Parcelable;
import android.os.Process;
import android.security.Credentials;
+import android.security.KeyChain;
import android.security.KeyStore;
import android.text.TextUtils;
+import android.util.Slog;
import java.io.ByteArrayInputStream;
import java.io.IOException;
@@ -43,6 +45,7 @@ import java.util.Map;
*/
public class WifiEnterpriseConfig implements Parcelable {
private static final String TAG = "WifiEnterpriseConfig";
+ private static final boolean DBG = false;
/**
* In old configurations, the "private_key" field was used. However, newer
* configurations use the key_id field with the engine_id set to "keystore".
@@ -91,6 +94,7 @@ public class WifiEnterpriseConfig implements Parcelable {
private X509Certificate mCaCert;
private PrivateKey mClientPrivateKey;
private X509Certificate mClientCertificate;
+ private boolean mNeedsSoftwareKeystore = false;
/** This represents an empty value of an enterprise field.
* NULL is used at wpa_supplicant to indicate an empty value
@@ -509,6 +513,18 @@ public class WifiEnterpriseConfig implements Parcelable {
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 ret = true;
String privKeyName = Credentials.USER_PRIVATE_KEY + name;
@@ -516,8 +532,23 @@ public class WifiEnterpriseConfig implements Parcelable {
String caCertName = Credentials.CA_CERTIFICATE + name;
if (mClientCertificate != null) {
byte[] privKeyData = mClientPrivateKey.getEncoded();
- ret = keyStore.importKey(privKeyName, privKeyData, Process.WIFI_UID,
- KeyStore.FLAG_ENCRYPTED);
+ 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,
+ KeyStore.FLAG_ENCRYPTED);
+ mNeedsSoftwareKeystore = true;
+ }
if (ret == false) {
return ret;
}
@@ -561,7 +592,9 @@ public class WifiEnterpriseConfig implements Parcelable {
Certificate cert) {
try {
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) {
return false;
} catch (CertificateException e2) {
@@ -573,6 +606,7 @@ public class WifiEnterpriseConfig implements Parcelable {
String client = getFieldValue(CLIENT_CERT_KEY, CLIENT_CERT_PREFIX);
// a valid client certificate is configured
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.delete(Credentials.USER_CERTIFICATE + client, Process.WIFI_UID);
}
@@ -580,6 +614,7 @@ public class WifiEnterpriseConfig implements Parcelable {
String ca = getFieldValue(CA_CERT_KEY, CA_CERT_PREFIX);
// a valid ca certificate is configured
if (!TextUtils.isEmpty(ca)) {
+ if (DBG) Slog.d(TAG, "removing CA cert");
keyStore.delete(Credentials.CA_CERTIFICATE + ca, Process.WIFI_UID);
}
}
@@ -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) {
if (TextUtils.isEmpty(string)) return "";
int length = string.length();
diff --git a/wifi/java/android/net/wifi/WifiStateMachine.java b/wifi/java/android/net/wifi/WifiStateMachine.java
index 798bc2e..cf09836 100644
--- a/wifi/java/android/net/wifi/WifiStateMachine.java
+++ b/wifi/java/android/net/wifi/WifiStateMachine.java
@@ -426,6 +426,8 @@ public class WifiStateMachine extends StateMachine {
static final int CMD_IP_ADDRESS_UPDATED = BASE + 140;
/* An IP address was removed from our interface */
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 */
/* CONNECT_MODE - connect to any 'known' AP when it becomes available */
@@ -1320,6 +1322,14 @@ public class WifiStateMachine extends StateMachine {
}
/**
+ * 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
*
* @return network id of the new network
@@ -2445,6 +2455,7 @@ public class WifiStateMachine extends StateMachine {
case CMD_DISCONNECT:
case CMD_RECONNECT:
case CMD_REASSOCIATE:
+ case CMD_RELOAD_TLS_AND_RECONNECT:
case WifiMonitor.SUP_CONNECTION_EVENT:
case WifiMonitor.SUP_DISCONNECTION_EVENT:
case WifiMonitor.NETWORK_CONNECTION_EVENT:
@@ -3395,6 +3406,13 @@ public class WifiStateMachine extends StateMachine {
case CMD_REASSOCIATE:
mWifiNative.reassociate();
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:
/* The connect message can contain a network id passed as arg1 on message or
* or a config passed as obj on message.