summaryrefslogtreecommitdiffstats
path: root/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
diff options
context:
space:
mode:
authorVinit Deshapnde <vinitd@google.com>2013-10-02 17:26:05 -0700
committerVinit Deshapnde <vinitd@google.com>2013-10-02 17:26:05 -0700
commita3038b2b311cd07d851c404ccc5df2f4e07bcfd8 (patch)
tree6099aefba7430212240b6aeb356bee9b7feb6211 /wifi/java/android/net/wifi/WifiEnterpriseConfig.java
parentd6957d5f8ddf3b542996955bf2d6efe0e9804ef4 (diff)
downloadframeworks_base-a3038b2b311cd07d851c404ccc5df2f4e07bcfd8.zip
frameworks_base-a3038b2b311cd07d851c404ccc5df2f4e07bcfd8.tar.gz
frameworks_base-a3038b2b311cd07d851c404ccc5df2f4e07bcfd8.tar.bz2
Fix EAP-TLS reconnect after reboot issue
After a reboot, KeyStore is locked, and certificates encrypted with user PIN are not accessible. So statemachines are not able to connect to EAP-TLS networks. This change makes the problem less severe by 1. Not signing certificates with user PIN on devices with hardware backed KeyStore. 2. Issuing a reconnect upon first USER_PRESENT event. This means HH (which has a hardware backed keystore) can connect to EAP-TLS networks without requiring user intervention and other devices will automatically connect to those networks after user punches PIN. Bug: 10325089 Change-Id: I023d60e58d8214152f051bd9ec84b85b702d829a
Diffstat (limited to 'wifi/java/android/net/wifi/WifiEnterpriseConfig.java')
-rw-r--r--wifi/java/android/net/wifi/WifiEnterpriseConfig.java96
1 files changed, 93 insertions, 3 deletions
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();