diff options
author | Vinit Deshapnde <vinitd@google.com> | 2013-10-04 11:08:06 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2013-10-04 11:08:06 -0700 |
commit | 1e9863f06ad4d006abb0a76677c246d1420d5352 (patch) | |
tree | faeee12dd245f74b6e352c1a69ff4b8b7249f393 /wifi | |
parent | 1ff5ad874ef8ad9e9e02cddfe35f793d0c15c47b (diff) | |
parent | 90a5192cd4af89a1b363ca25be2a63d0e57010d4 (diff) | |
download | frameworks_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')
-rw-r--r-- | wifi/java/android/net/wifi/WifiConfigStore.java | 23 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiEnterpriseConfig.java | 96 | ||||
-rw-r--r-- | wifi/java/android/net/wifi/WifiStateMachine.java | 18 |
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. |