diff options
| -rw-r--r-- | api/system-current.txt | 2 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/RttManager.java | 14 | ||||
| -rw-r--r-- | wifi/java/android/net/wifi/WifiEnterpriseConfig.java | 200 |
3 files changed, 183 insertions, 33 deletions
diff --git a/api/system-current.txt b/api/system-current.txt index a03f3283a532..3706140aa36f 100644 --- a/api/system-current.txt +++ b/api/system-current.txt @@ -20815,6 +20815,7 @@ package android.net.wifi { field public int numberBurst; field public int preamble; field public int requestType; + field public boolean secure; } public static class RttManager.RttResult { @@ -20846,6 +20847,7 @@ package android.net.wifi { field public deprecated long rtt_sd_ns; field public deprecated long rtt_spread_ns; field public int rxRate; + field public boolean secure; field public int status; field public int successMeasurementFrameNumber; field public long ts; diff --git a/wifi/java/android/net/wifi/RttManager.java b/wifi/java/android/net/wifi/RttManager.java index 9137d9d90439..249f64f3788c 100644 --- a/wifi/java/android/net/wifi/RttManager.java +++ b/wifi/java/android/net/wifi/RttManager.java @@ -324,6 +324,11 @@ public class RttManager { public int requestType; /** + * Whether the secure RTT protocol needs to be used for ranging this peer device. + */ + public boolean secure; + + /** * mac address of the device being ranged * Default value: null */ @@ -478,6 +483,7 @@ public class RttManager { for (RttParams params : mParams) { dest.writeInt(params.deviceType); dest.writeInt(params.requestType); + dest.writeByte(params.secure ? (byte) 1 : 0); dest.writeString(params.bssid); dest.writeInt(params.channelWidth); dest.writeInt(params.frequency); @@ -515,6 +521,7 @@ public class RttManager { params[i] = new RttParams(); params[i].deviceType = in.readInt(); params[i].requestType = in.readInt(); + params[i].secure = (in.readByte() != 0); params[i].bssid = in.readString(); params[i].channelWidth = in.readInt(); params[i].frequency = in.readInt(); @@ -690,6 +697,11 @@ public class RttManager { /** LCR information Element, only available to double side RTT. */ public WifiInformationElement LCR; + + /** + * Whether the secure RTT protocol was used for ranging. + */ + public boolean secure; } @@ -742,6 +754,7 @@ public class RttManager { dest.writeInt((byte) result.LCR.data.length); dest.writeByte(result.LCR.id); } + dest.writeByte(result.secure ? (byte) 1 : 0); } } else { dest.writeInt(0); @@ -796,6 +809,7 @@ public class RttManager { results[i].LCR.data = new byte[length]; in.readByteArray(results[i].LCR.data); } + results[i].secure = (in.readByte() != 0); } ParcelableRttResults parcelableResults = new ParcelableRttResults(results); diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java index a406fd75cfbd..964bfa2f011b 100644 --- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java +++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java @@ -20,6 +20,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.security.Credentials; import android.text.TextUtils; +import android.util.Log; import java.io.ByteArrayInputStream; import java.nio.charset.StandardCharsets; @@ -122,6 +123,22 @@ public class WifiEnterpriseConfig implements Parcelable { /** {@hide} */ public static final String DISABLE_TLS_1_2 = "\"tls_disable_tlsv1_2=1\""; + // Fields to copy verbatim from wpa_supplicant. + private static final String[] SUPPLICANT_CONFIG_KEYS = new String[] { + IDENTITY_KEY, + ANON_IDENTITY_KEY, + PASSWORD_KEY, + CLIENT_CERT_KEY, + CA_CERT_KEY, + SUBJECT_MATCH_KEY, + ENGINE_KEY, + ENGINE_ID_KEY, + PRIVATE_KEY_ID_KEY, + ALTSUBJECT_MATCH_KEY, + DOM_SUFFIX_MATCH_KEY, + CA_PATH_KEY + }; + private HashMap<String, String> mFields = new HashMap<String, String>(); //By default, we enable TLS1.2. However, due to a known bug on some radius, we may disable it to // fall back to TLS 1.1. @@ -129,6 +146,10 @@ public class WifiEnterpriseConfig implements Parcelable { private X509Certificate[] mCaCerts; private PrivateKey mClientPrivateKey; private X509Certificate mClientCertificate; + private int mEapMethod = Eap.NONE; + private int mPhase2Method = Phase2.NONE; + + private static final String TAG = "WifiEnterpriseConfig"; public WifiEnterpriseConfig() { // Do not set defaults so that the enterprise fields that are not changed @@ -143,6 +164,8 @@ public class WifiEnterpriseConfig implements Parcelable { for (String key : source.mFields.keySet()) { mFields.put(key, source.mFields.get(key)); } + mEapMethod = source.mEapMethod; + mPhase2Method = source.mPhase2Method; } @Override @@ -158,6 +181,8 @@ public class WifiEnterpriseConfig implements Parcelable { dest.writeString(entry.getValue()); } + dest.writeInt(mEapMethod); + dest.writeInt(mPhase2Method); writeCertificates(dest, mCaCerts); if (mClientPrivateKey != null) { @@ -210,6 +235,8 @@ public class WifiEnterpriseConfig implements Parcelable { enterpriseConfig.mFields.put(key, value); } + enterpriseConfig.mEapMethod = in.readInt(); + enterpriseConfig.mPhase2Method = in.readInt(); enterpriseConfig.mCaCerts = readCertificates(in); PrivateKey userKey = null; @@ -307,7 +334,8 @@ public class WifiEnterpriseConfig implements Parcelable { public static final int MSCHAPV2 = 3; /** Generic Token Card */ public static final int GTC = 4; - private static final String PREFIX = "auth="; + private static final String AUTH_PREFIX = "auth="; + private static final String AUTHEAP_PREFIX = "autheap="; /** @hide */ public static final String[] strings = {EMPTY_VALUE, "PAP", "MSCHAP", "MSCHAPV2", "GTC" }; @@ -316,11 +344,98 @@ public class WifiEnterpriseConfig implements Parcelable { private Phase2() {} } - /** Internal use only + // Loader and saver interfaces for exchanging data with wpa_supplicant. + // TODO: Decouple this object (which is just a placeholder of the configuration) + // from the implementation that knows what wpa_supplicant wants. + /** + * Interface used for retrieving supplicant configuration from WifiEnterpriseConfig + * @hide + */ + public interface SupplicantSaver { + /** + * Set a value within wpa_supplicant configuration + * @param key index to set within wpa_supplciant + * @param value the value for the key + * @return true if successful; false otherwise + */ + boolean saveValue(String key, String value); + } + + /** + * Interface used for populating a WifiEnterpriseConfig from supplicant configuration + * @hide + */ + public interface SupplicantLoader { + /** + * Returns a value within wpa_supplicant configuration + * @param key index to set within wpa_supplciant + * @return string value if successful; null otherwise + */ + String loadValue(String key); + } + + /** + * Internal use only; supply field values to wpa_supplicant config. The configuration + * process aborts on the first failed call on {@code saver}. + * @param saver proxy for setting configuration in wpa_supplciant + * @return whether the save succeeded on all attempts + * @hide + */ + public boolean saveToSupplicant(SupplicantSaver saver) { + if (!isEapMethodValid()) { + return false; + } + + for (String key : mFields.keySet()) { + if (!saver.saveValue(key, mFields.get(key))) { + return false; + } + } + + if (!saver.saveValue(EAP_KEY, Eap.strings[mEapMethod])) { + return false; + } + + if (mEapMethod != Eap.TLS && mPhase2Method != Phase2.NONE) { + boolean is_autheap = mEapMethod == Eap.TTLS && mPhase2Method == Phase2.GTC; + String prefix = is_autheap ? Phase2.AUTHEAP_PREFIX : Phase2.AUTH_PREFIX; + String value = convertToQuotedString(prefix + Phase2.strings[mPhase2Method]); + return saver.saveValue(PHASE2_KEY, value); + } else if (mPhase2Method == Phase2.NONE) { + // By default, send a null phase 2 to clear old configuration values. + return saver.saveValue(PHASE2_KEY, null); + } else { + Log.e(TAG, "WiFi enterprise configuration is invalid as it supplies a " + + "phase 2 method but the phase1 method does not support it."); + return false; + } + } + + /** + * Internal use only; retrieve configuration from wpa_supplicant config. + * @param loader proxy for retrieving configuration keys from wpa_supplicant * @hide */ - public HashMap<String, String> getFields() { - return mFields; + public void loadFromSupplicant(SupplicantLoader loader) { + for (String key : SUPPLICANT_CONFIG_KEYS) { + String value = loader.loadValue(key); + if (value == null) { + mFields.put(key, EMPTY_VALUE); + } else { + mFields.put(key, value); + } + } + String eapMethod = loader.loadValue(EAP_KEY); + mEapMethod = getStringIndex(Eap.strings, eapMethod, Eap.NONE); + + String phase2Method = removeDoubleQuotes(loader.loadValue(PHASE2_KEY)); + // Remove "auth=" or "autheap=" prefix. + if (phase2Method.startsWith(Phase2.AUTH_PREFIX)) { + phase2Method = phase2Method.substring(Phase2.AUTH_PREFIX.length()); + } else if (phase2Method.startsWith(Phase2.AUTHEAP_PREFIX)) { + phase2Method = phase2Method.substring(Phase2.AUTHEAP_PREFIX.length()); + } + mPhase2Method = getStringIndex(Phase2.strings, phase2Method, Phase2.NONE); } /** @@ -341,7 +456,7 @@ public class WifiEnterpriseConfig implements Parcelable { case Eap.SIM: case Eap.AKA: case Eap.AKA_PRIME: - mFields.put(EAP_KEY, Eap.strings[eapMethod]); + mEapMethod = eapMethod; mFields.put(OPP_KEY_CACHING, "1"); break; default: @@ -374,8 +489,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @return eap method configured */ public int getEapMethod() { - String eapMethod = mFields.get(EAP_KEY); - return getStringIndex(Eap.strings, eapMethod, Eap.NONE); + return mEapMethod; } /** @@ -390,15 +504,11 @@ public class WifiEnterpriseConfig implements Parcelable { public void setPhase2Method(int phase2Method) { switch (phase2Method) { case Phase2.NONE: - mFields.put(PHASE2_KEY, EMPTY_VALUE); - break; - /** Valid methods */ case Phase2.PAP: case Phase2.MSCHAP: case Phase2.MSCHAPV2: case Phase2.GTC: - mFields.put(PHASE2_KEY, convertToQuotedString( - Phase2.PREFIX + Phase2.strings[phase2Method])); + mPhase2Method = phase2Method; break; default: throw new IllegalArgumentException("Unknown Phase 2 method"); @@ -410,12 +520,7 @@ public class WifiEnterpriseConfig implements Parcelable { * @return a phase 2 method defined at {@link Phase2} * */ public int getPhase2Method() { - String phase2Method = removeDoubleQuotes(mFields.get(PHASE2_KEY)); - // Remove auth= prefix - if (phase2Method.startsWith(Phase2.PREFIX)) { - phase2Method = phase2Method.substring(Phase2.PREFIX.length()); - } - return getStringIndex(Phase2.strings, phase2Method, Phase2.NONE); + return mPhase2Method; } /** @@ -443,7 +548,8 @@ public class WifiEnterpriseConfig implements Parcelable { setFieldValue(ANON_IDENTITY_KEY, anonymousIdentity, ""); } - /** Get the anonymous identity + /** + * Get the anonymous identity * @return anonymous identity */ public String getAnonymousIdentity() { @@ -870,18 +976,15 @@ public class WifiEnterpriseConfig implements Parcelable { } /** See {@link WifiConfiguration#getKeyIdForCredentials} @hide */ - String getKeyId(WifiEnterpriseConfig current) { - String eap = mFields.get(EAP_KEY); - String phase2 = mFields.get(PHASE2_KEY); - - // If either eap or phase2 are not initialized, use current config details - if (TextUtils.isEmpty((eap))) { - eap = current.mFields.get(EAP_KEY); + public String getKeyId(WifiEnterpriseConfig current) { + // If EAP method is not initialized, use current config details + if (mEapMethod == Eap.NONE) { + return (current != null) ? current.getKeyId(null) : EMPTY_VALUE; } - if (TextUtils.isEmpty(phase2)) { - phase2 = current.mFields.get(PHASE2_KEY); + if (!isEapMethodValid()) { + return EMPTY_VALUE; } - return eap + "_" + phase2; + return Eap.strings[mEapMethod] + "_" + Phase2.strings[mPhase2Method]; } private String removeDoubleQuotes(String string) { @@ -898,7 +1001,8 @@ public class WifiEnterpriseConfig implements Parcelable { return "\"" + string + "\""; } - /** Returns the index at which the toBeFound string is found in the array. + /** + * Returns the index at which the toBeFound string is found in the array. * @param arr array of strings * @param toBeFound string to be found * @param defaultIndex default index to be returned when string is not found @@ -912,13 +1016,16 @@ public class WifiEnterpriseConfig implements Parcelable { return defaultIndex; } - /** Returns the field value for the key. + /** + * Returns the field value for the key. * @param key into the hash * @param prefix is the prefix that the value may have * @return value * @hide */ public String getFieldValue(String key, String prefix) { + // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since + // neither of these keys should be retrieved in this manner. String value = mFields.get(key); // Uninitialized or known to be empty after reading from supplicant if (TextUtils.isEmpty(value) || EMPTY_VALUE.equals(value)) return ""; @@ -931,13 +1038,16 @@ public class WifiEnterpriseConfig implements Parcelable { } } - /** Set a value with an optional prefix at key + /** + * Set a value with an optional prefix at key * @param key into the hash * @param value to be set * @param prefix an optional value to be prefixed to actual value * @hide */ public void setFieldValue(String key, String value, String prefix) { + // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since + // neither of these keys should be set in this manner. if (TextUtils.isEmpty(value)) { mFields.put(key, EMPTY_VALUE); } else { @@ -946,13 +1056,16 @@ public class WifiEnterpriseConfig implements Parcelable { } - /** Set a value with an optional prefix at key + /** + * Set a value with an optional prefix at key * @param key into the hash * @param value to be set * @param prefix an optional value to be prefixed to actual value * @hide */ public void setFieldValue(String key, String value) { + // TODO: Should raise an exception if |key| is EAP_KEY or PHASE2_KEY since + // neither of these keys should be set in this manner. if (TextUtils.isEmpty(value)) { mFields.put(key, EMPTY_VALUE); } else { @@ -968,4 +1081,25 @@ public class WifiEnterpriseConfig implements Parcelable { } return sb.toString(); } + + /** + * Returns whether the EAP method data is valid, i.e., whether mEapMethod and mPhase2Method + * are valid indices into {@code Eap.strings[]} and {@code Phase2.strings[]} respectively. + */ + private boolean isEapMethodValid() { + if (mEapMethod == Eap.NONE) { + Log.e(TAG, "WiFi enterprise configuration is invalid as it supplies no EAP method."); + return false; + } + if (mEapMethod < 0 || mEapMethod >= Eap.strings.length) { + Log.e(TAG, "mEapMethod is invald for WiFi enterprise configuration: " + mEapMethod); + return false; + } + if (mPhase2Method < 0 || mPhase2Method >= Phase2.strings.length) { + Log.e(TAG, "mPhase2Method is invald for WiFi enterprise configuration: " + + mPhase2Method); + return false; + } + return true; + } } |