diff options
author | Roshan Pius <rpius@google.com> | 2019-10-22 16:38:36 -0700 |
---|---|---|
committer | Roshan Pius <rpius@google.com> | 2019-11-14 12:12:55 -0800 |
commit | 09621a42f86690346814c48cf1cdb1f123402e12 (patch) | |
tree | 52a587e81b7b78424e1c5797bdc80cc6072046ae | |
parent | 6237115f3c6ae723eb3927640c843714793fbe59 (diff) |
WifiConfigStore: Encrypt credentials for networks (3/4)
Encrypt/Decrypt preSharedKey & enterprise config's password fields.
When deserializing, handle migration from older config store
version file.
Any encryption failure are silently ignored. Decryption failures are
however non-recoverable.
Bug: 140485110
Test: atest com.android.server.wifi
Test: Manual verification
- Store a PSK network config on older build
- Upgrade to build with this CL
- Ensured that the psk was read correctly on upgrade
- Ensured that the psk was encrypted when stored on disk after upgrade
Change-Id: Ic7673cb375c9e5447ff4074ed78321152573e1c3
Merged-In: Ic7673cb375c9e5447ff4074ed78321152573e1c3
5 files changed, 429 insertions, 242 deletions
diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index dee52a795..350e8b52f 100644 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -170,12 +170,6 @@ public class WifiConfigStore { put(STORE_FILE_USER_GENERAL, STORE_FILE_NAME_USER_GENERAL); put(STORE_FILE_USER_NETWORK_SUGGESTIONS, STORE_FILE_NAME_USER_NETWORK_SUGGESTIONS); }}; - - @VisibleForTesting - public static final EncryptedData ZEROED_ENCRYPTED_DATA = - new EncryptedData( - new byte[EncryptedData.ENCRYPTED_DATA_LENGTH], - new byte[EncryptedData.IV_LENGTH]); /** * Handler instance to post alarm timeouts to */ diff --git a/service/java/com/android/server/wifi/util/EncryptedData.java b/service/java/com/android/server/wifi/util/EncryptedData.java index 91342d335..baec20426 100644 --- a/service/java/com/android/server/wifi/util/EncryptedData.java +++ b/service/java/com/android/server/wifi/util/EncryptedData.java @@ -18,21 +18,19 @@ package com.android.server.wifi.util; import com.android.internal.util.Preconditions; +import java.util.Arrays; +import java.util.Objects; + /** - * A class to store data created by {@link DataIntegrityChecker}. + * A class to store data created by {@link WifiConfigStoreEncryptionUtil}. */ public class EncryptedData { - public static final int ENCRYPTED_DATA_LENGTH = 48; - public static final int IV_LENGTH = 12; - private final byte[] mEncryptedData; private final byte[] mIv; public EncryptedData(byte[] encryptedData, byte[] iv) { - Preconditions.checkNotNull(encryptedData, iv); - Preconditions.checkState(encryptedData.length == ENCRYPTED_DATA_LENGTH, - "encryptedData.length=" + encryptedData.length); - Preconditions.checkState(iv.length == IV_LENGTH, "iv.length=" + iv.length); + Preconditions.checkNotNull(encryptedData); + Preconditions.checkNotNull(iv); mEncryptedData = encryptedData; mIv = iv; } @@ -44,4 +42,17 @@ public class EncryptedData { public byte[] getIv() { return mIv; } + + @Override + public boolean equals(Object other) { + if (!(other instanceof EncryptedData)) return false; + EncryptedData otherEncryptedData = (EncryptedData) other; + return Arrays.equals(this.mEncryptedData, otherEncryptedData.mEncryptedData) + && Arrays.equals(this.mIv, otherEncryptedData.mIv); + } + + @Override + public int hashCode() { + return Objects.hash(Arrays.hashCode(mEncryptedData), Arrays.hashCode(mIv)); + } } diff --git a/service/java/com/android/server/wifi/util/XmlUtil.java b/service/java/com/android/server/wifi/util/XmlUtil.java index 292c7929a..6128b0b4c 100644 --- a/service/java/com/android/server/wifi/util/XmlUtil.java +++ b/service/java/com/android/server/wifi/util/XmlUtil.java @@ -30,6 +30,7 @@ import android.net.StaticIpConfiguration; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiConfiguration.NetworkSelectionStatus; import android.net.wifi.WifiEnterpriseConfig; +import android.text.TextUtils; import android.util.Log; import android.util.Pair; @@ -379,12 +380,42 @@ public class XmlUtil { } /** + * Write preshared key to the XML stream. + * + * If encryptionUtil is null or if encryption fails for some reason, the pre-shared + * key is stored in plaintext, else the encrypted psk is stored. + */ + private static void writePreSharedKeyToXml( + XmlSerializer out, String preSharedKey, + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) + throws XmlPullParserException, IOException { + EncryptedData encryptedData = null; + if (encryptionUtil != null) { + if (preSharedKey != null) { + encryptedData = encryptionUtil.encrypt(preSharedKey.getBytes()); + if (encryptedData == null) { + // We silently fail encryption failures! + Log.wtf(TAG, "Encryption of preSharedKey failed"); + } + } + } + if (encryptedData != null) { + XmlUtil.writeNextSectionStart(out, XML_TAG_PRE_SHARED_KEY); + EncryptedDataXmlUtil.writeToXml(out, encryptedData); + XmlUtil.writeNextSectionEnd(out, XML_TAG_PRE_SHARED_KEY); + } else { + XmlUtil.writeNextValue(out, XML_TAG_PRE_SHARED_KEY, preSharedKey); + } + } + + /** * Write the Configuration data elements that are common for backup & config store to the * XML stream. * * @param out XmlSerializer instance pointing to the XML stream. * @param configuration WifiConfiguration object to be serialized. - * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. + * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. Backup/restore stores + * keys unencrypted. */ public static void writeCommonElementsToXml( XmlSerializer out, WifiConfiguration configuration, @@ -393,7 +424,7 @@ public class XmlUtil { XmlUtil.writeNextValue(out, XML_TAG_CONFIG_KEY, configuration.configKey()); XmlUtil.writeNextValue(out, XML_TAG_SSID, configuration.SSID); XmlUtil.writeNextValue(out, XML_TAG_BSSID, configuration.BSSID); - XmlUtil.writeNextValue(out, XML_TAG_PRE_SHARED_KEY, configuration.preSharedKey); + writePreSharedKeyToXml(out, configuration.preSharedKey, encryptionUtil); writeWepKeysToXml(out, configuration.wepKeys); XmlUtil.writeNextValue(out, XML_TAG_WEP_TX_KEY_INDEX, configuration.wepTxKeyIndex); XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, configuration.hiddenSSID); @@ -517,13 +548,13 @@ public class XmlUtil { * * @param in XmlPullParser instance pointing to the XML stream. * @param outerTagDepth depth of the outer tag in the XML document. - * @param areCredentialsEncrypted Whether credentials are encrypted or not. + * @param shouldExpectEncryptedCredentials Whether to expect encrypted credentials or not. * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. * @return Pair<Config key, WifiConfiguration object> if parsing is successful, * null otherwise. */ public static Pair<String, WifiConfiguration> parseFromXml( - XmlPullParser in, int outerTagDepth, boolean areCredentialsEncrypted, + XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { WifiConfiguration configuration = new WifiConfiguration(); @@ -532,147 +563,175 @@ public class XmlUtil { // Loop through and parse out all the elements from the stream within this section. while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { - String[] valueName = new String[1]; - Object value = XmlUtil.readCurrentValue(in, valueName); - if (valueName[0] == null) { - throw new XmlPullParserException("Missing value name"); - } - switch (valueName[0]) { - case XML_TAG_CONFIG_KEY: - configKeyInData = (String) value; - break; - case XML_TAG_SSID: - configuration.SSID = (String) value; - break; - case XML_TAG_BSSID: - configuration.BSSID = (String) value; - break; - case XML_TAG_PRE_SHARED_KEY: - configuration.preSharedKey = (String) value; - break; - case XML_TAG_WEP_KEYS: - populateWepKeysFromXmlValue(value, configuration.wepKeys); - break; - case XML_TAG_WEP_TX_KEY_INDEX: - configuration.wepTxKeyIndex = (int) value; - break; - case XML_TAG_HIDDEN_SSID: - configuration.hiddenSSID = (boolean) value; - break; - case XML_TAG_REQUIRE_PMF: - configuration.requirePMF = (boolean) value; - break; - case XML_TAG_ALLOWED_KEY_MGMT: - byte[] allowedKeyMgmt = (byte[]) value; - configuration.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt); - break; - case XML_TAG_ALLOWED_PROTOCOLS: - byte[] allowedProtocols = (byte[]) value; - configuration.allowedProtocols = BitSet.valueOf(allowedProtocols); - break; - case XML_TAG_ALLOWED_AUTH_ALGOS: - byte[] allowedAuthAlgorithms = (byte[]) value; - configuration.allowedAuthAlgorithms = BitSet.valueOf(allowedAuthAlgorithms); - break; - case XML_TAG_ALLOWED_GROUP_CIPHERS: - byte[] allowedGroupCiphers = (byte[]) value; - configuration.allowedGroupCiphers = BitSet.valueOf(allowedGroupCiphers); - break; - case XML_TAG_ALLOWED_PAIRWISE_CIPHERS: - byte[] allowedPairwiseCiphers = (byte[]) value; - configuration.allowedPairwiseCiphers = - BitSet.valueOf(allowedPairwiseCiphers); - break; - case XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS: - byte[] allowedGroupMgmtCiphers = (byte[]) value; - configuration.allowedGroupManagementCiphers = - BitSet.valueOf(allowedGroupMgmtCiphers); - break; - case XML_TAG_ALLOWED_SUITE_B_CIPHERS: - byte[] allowedSuiteBCiphers = (byte[]) value; - configuration.allowedSuiteBCiphers = - BitSet.valueOf(allowedSuiteBCiphers); - break; - case XML_TAG_SHARED: - configuration.shared = (boolean) value; - break; - case XML_TAG_STATUS: - int status = (int) value; - // Any network which was CURRENT before reboot needs - // to be restored to ENABLED. - if (status == WifiConfiguration.Status.CURRENT) { - status = WifiConfiguration.Status.ENABLED; - } - configuration.status = status; - break; - case XML_TAG_FQDN: - configuration.FQDN = (String) value; - break; - case XML_TAG_PROVIDER_FRIENDLY_NAME: - configuration.providerFriendlyName = (String) value; - break; - case XML_TAG_LINKED_NETWORKS_LIST: - configuration.linkedConfigurations = (HashMap<String, Integer>) value; - break; - case XML_TAG_DEFAULT_GW_MAC_ADDRESS: - configuration.defaultGwMacAddress = (String) value; - break; - case XML_TAG_VALIDATED_INTERNET_ACCESS: - configuration.validatedInternetAccess = (boolean) value; - break; - case XML_TAG_NO_INTERNET_ACCESS_EXPECTED: - configuration.noInternetAccessExpected = (boolean) value; - break; - case XML_TAG_USER_APPROVED: - configuration.userApproved = (int) value; - break; - case XML_TAG_METERED_HINT: - configuration.meteredHint = (boolean) value; - break; - case XML_TAG_METERED_OVERRIDE: - configuration.meteredOverride = (int) value; - break; - case XML_TAG_USE_EXTERNAL_SCORES: - configuration.useExternalScores = (boolean) value; - break; - case XML_TAG_NUM_ASSOCIATION: - configuration.numAssociation = (int) value; - break; - case XML_TAG_CREATOR_UID: - configuration.creatorUid = (int) value; - break; - case XML_TAG_CREATOR_NAME: - configuration.creatorName = (String) value; - break; - case XML_TAG_CREATION_TIME: - configuration.creationTime = (String) value; - break; - case XML_TAG_LAST_UPDATE_UID: - configuration.lastUpdateUid = (int) value; - break; - case XML_TAG_LAST_UPDATE_NAME: - configuration.lastUpdateName = (String) value; - break; - case XML_TAG_LAST_CONNECT_UID: - configuration.lastConnectUid = (int) value; - break; - case XML_TAG_IS_LEGACY_PASSPOINT_CONFIG: - configuration.isLegacyPasspointConfig = (boolean) value; - break; - case XML_TAG_ROAMING_CONSORTIUM_OIS: - configuration.roamingConsortiumIds = (long[]) value; - break; - case XML_TAG_RANDOMIZED_MAC_ADDRESS: - configuration.setRandomizedMacAddress( - MacAddress.fromString((String) value)); - break; - case XML_TAG_MAC_RANDOMIZATION_SETTING: - configuration.macRandomizationSetting = (int) value; - macRandomizationSettingExists = true; - break; - default: - throw new XmlPullParserException( - "Unknown value name found: " + valueName[0]); + if (in.getAttributeValue(null, "name") != null) { + // Value elements. + String[] valueName = new String[1]; + Object value = XmlUtil.readCurrentValue(in, valueName); + if (valueName[0] == null) { + throw new XmlPullParserException("Missing value name"); + } + switch (valueName[0]) { + case XML_TAG_CONFIG_KEY: + configKeyInData = (String) value; + break; + case XML_TAG_SSID: + configuration.SSID = (String) value; + break; + case XML_TAG_BSSID: + configuration.BSSID = (String) value; + break; + case XML_TAG_PRE_SHARED_KEY: + configuration.preSharedKey = (String) value; + break; + case XML_TAG_WEP_KEYS: + populateWepKeysFromXmlValue(value, configuration.wepKeys); + break; + case XML_TAG_WEP_TX_KEY_INDEX: + configuration.wepTxKeyIndex = (int) value; + break; + case XML_TAG_HIDDEN_SSID: + configuration.hiddenSSID = (boolean) value; + break; + case XML_TAG_REQUIRE_PMF: + configuration.requirePMF = (boolean) value; + break; + case XML_TAG_ALLOWED_KEY_MGMT: + byte[] allowedKeyMgmt = (byte[]) value; + configuration.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt); + break; + case XML_TAG_ALLOWED_PROTOCOLS: + byte[] allowedProtocols = (byte[]) value; + configuration.allowedProtocols = BitSet.valueOf(allowedProtocols); + break; + case XML_TAG_ALLOWED_AUTH_ALGOS: + byte[] allowedAuthAlgorithms = (byte[]) value; + configuration.allowedAuthAlgorithms = BitSet.valueOf( + allowedAuthAlgorithms); + break; + case XML_TAG_ALLOWED_GROUP_CIPHERS: + byte[] allowedGroupCiphers = (byte[]) value; + configuration.allowedGroupCiphers = BitSet.valueOf(allowedGroupCiphers); + break; + case XML_TAG_ALLOWED_PAIRWISE_CIPHERS: + byte[] allowedPairwiseCiphers = (byte[]) value; + configuration.allowedPairwiseCiphers = + BitSet.valueOf(allowedPairwiseCiphers); + break; + case XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS: + byte[] allowedGroupMgmtCiphers = (byte[]) value; + configuration.allowedGroupManagementCiphers = + BitSet.valueOf(allowedGroupMgmtCiphers); + break; + case XML_TAG_ALLOWED_SUITE_B_CIPHERS: + byte[] allowedSuiteBCiphers = (byte[]) value; + configuration.allowedSuiteBCiphers = + BitSet.valueOf(allowedSuiteBCiphers); + break; + case XML_TAG_SHARED: + configuration.shared = (boolean) value; + break; + case XML_TAG_STATUS: + int status = (int) value; + // Any network which was CURRENT before reboot needs + // to be restored to ENABLED. + if (status == WifiConfiguration.Status.CURRENT) { + status = WifiConfiguration.Status.ENABLED; + } + configuration.status = status; + break; + case XML_TAG_FQDN: + configuration.FQDN = (String) value; + break; + case XML_TAG_PROVIDER_FRIENDLY_NAME: + configuration.providerFriendlyName = (String) value; + break; + case XML_TAG_LINKED_NETWORKS_LIST: + configuration.linkedConfigurations = (HashMap<String, Integer>) value; + break; + case XML_TAG_DEFAULT_GW_MAC_ADDRESS: + configuration.defaultGwMacAddress = (String) value; + break; + case XML_TAG_VALIDATED_INTERNET_ACCESS: + configuration.validatedInternetAccess = (boolean) value; + break; + case XML_TAG_NO_INTERNET_ACCESS_EXPECTED: + configuration.noInternetAccessExpected = (boolean) value; + break; + case XML_TAG_USER_APPROVED: + configuration.userApproved = (int) value; + break; + case XML_TAG_METERED_HINT: + configuration.meteredHint = (boolean) value; + break; + case XML_TAG_METERED_OVERRIDE: + configuration.meteredOverride = (int) value; + break; + case XML_TAG_USE_EXTERNAL_SCORES: + configuration.useExternalScores = (boolean) value; + break; + case XML_TAG_NUM_ASSOCIATION: + configuration.numAssociation = (int) value; + break; + case XML_TAG_CREATOR_UID: + configuration.creatorUid = (int) value; + break; + case XML_TAG_CREATOR_NAME: + configuration.creatorName = (String) value; + break; + case XML_TAG_CREATION_TIME: + configuration.creationTime = (String) value; + break; + case XML_TAG_LAST_UPDATE_UID: + configuration.lastUpdateUid = (int) value; + break; + case XML_TAG_LAST_UPDATE_NAME: + configuration.lastUpdateName = (String) value; + break; + case XML_TAG_LAST_CONNECT_UID: + configuration.lastConnectUid = (int) value; + break; + case XML_TAG_IS_LEGACY_PASSPOINT_CONFIG: + configuration.isLegacyPasspointConfig = (boolean) value; + break; + case XML_TAG_ROAMING_CONSORTIUM_OIS: + configuration.roamingConsortiumIds = (long[]) value; + break; + case XML_TAG_RANDOMIZED_MAC_ADDRESS: + configuration.setRandomizedMacAddress( + MacAddress.fromString((String) value)); + break; + case XML_TAG_MAC_RANDOMIZATION_SETTING: + configuration.macRandomizationSetting = (int) value; + macRandomizationSettingExists = true; + break; + default: + throw new XmlPullParserException( + "Unknown value name found: " + valueName[0]); + } + } else { + String tagName = in.getName(); + if (tagName == null) { + throw new XmlPullParserException("Unexpected null tag found"); + } + switch (tagName) { + case XML_TAG_PRE_SHARED_KEY: + if (!shouldExpectEncryptedCredentials) { + throw new XmlPullParserException( + "Encrypted preSharedKey section not expected"); + } + EncryptedData encryptedData = + EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1); + byte[] preSharedKeyBytes = encryptionUtil.decrypt(encryptedData); + if (preSharedKeyBytes == null) { + Log.wtf(TAG, "Decryption of preSharedKey failed"); + } else { + configuration.preSharedKey = new String(preSharedKeyBytes); + } + break; + default: + throw new XmlPullParserException( + "Unknown tag name found: " + tagName); + } } } if (!macRandomizationSettingExists) { @@ -1028,6 +1087,35 @@ public class XmlUtil { public static final String XML_TAG_REALM = "Realm"; /** + * Write password key to the XML stream. + * + * If encryptionUtil is null or if encryption fails for some reason, the password is stored + * in plaintext, else the encrypted psk is stored. + */ + private static void writePasswordToXml( + XmlSerializer out, String password, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + throws XmlPullParserException, IOException { + EncryptedData encryptedData = null; + if (encryptionUtil != null) { + if (password != null) { + encryptedData = encryptionUtil.encrypt(password.getBytes()); + if (encryptedData == null) { + // We silently fail encryption failures! + Log.wtf(TAG, "Encryption of password failed"); + } + } + } + if (encryptedData != null) { + XmlUtil.writeNextSectionStart(out, XML_TAG_PASSWORD); + EncryptedDataXmlUtil.writeToXml(out, encryptedData); + XmlUtil.writeNextSectionEnd(out, XML_TAG_PASSWORD); + } else { + XmlUtil.writeNextValue(out, XML_TAG_PASSWORD, password); + } + } + + /** * Write the WifiEnterpriseConfig data elements from the provided config to the XML * stream. * @@ -1042,8 +1130,9 @@ public class XmlUtil { enterpriseConfig.getFieldValue(WifiEnterpriseConfig.IDENTITY_KEY)); XmlUtil.writeNextValue(out, XML_TAG_ANON_IDENTITY, enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ANON_IDENTITY_KEY)); - XmlUtil.writeNextValue(out, XML_TAG_PASSWORD, - enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PASSWORD_KEY)); + writePasswordToXml( + out, enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PASSWORD_KEY), + encryptionUtil); XmlUtil.writeNextValue(out, XML_TAG_CLIENT_CERT, enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CLIENT_CERT_KEY)); XmlUtil.writeNextValue(out, XML_TAG_CA_CERT, @@ -1073,87 +1162,123 @@ public class XmlUtil { * * @param in XmlPullParser instance pointing to the XML stream. * @param outerTagDepth depth of the outer tag in the XML document. - * @param areCredentialsEncrypted Whether credentials are encrypted or not. + * @param shouldExpectEncryptedCredentials Whether to expect encrypted credentials or not. * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. * @return WifiEnterpriseConfig object if parsing is successful, null otherwise. */ public static WifiEnterpriseConfig parseFromXml(XmlPullParser in, int outerTagDepth, - boolean areCredentialsEncrypted, + boolean shouldExpectEncryptedCredentials, @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); // Loop through and parse out all the elements from the stream within this section. - while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { - String[] valueName = new String[1]; - Object value = XmlUtil.readCurrentValue(in, valueName); - if (valueName[0] == null) { - throw new XmlPullParserException("Missing value name"); - } - switch (valueName[0]) { - case XML_TAG_IDENTITY: - enterpriseConfig.setFieldValue( - WifiEnterpriseConfig.IDENTITY_KEY, (String) value); - break; - case XML_TAG_ANON_IDENTITY: - enterpriseConfig.setFieldValue( - WifiEnterpriseConfig.ANON_IDENTITY_KEY, (String) value); - break; - case XML_TAG_PASSWORD: - enterpriseConfig.setFieldValue( - WifiEnterpriseConfig.PASSWORD_KEY, (String) value); - break; - case XML_TAG_CLIENT_CERT: - enterpriseConfig.setFieldValue( - WifiEnterpriseConfig.CLIENT_CERT_KEY, (String) value); - break; - case XML_TAG_CA_CERT: - enterpriseConfig.setFieldValue( - WifiEnterpriseConfig.CA_CERT_KEY, (String) value); - break; - case XML_TAG_SUBJECT_MATCH: - enterpriseConfig.setFieldValue( - WifiEnterpriseConfig.SUBJECT_MATCH_KEY, (String) value); - break; - case XML_TAG_ENGINE: - enterpriseConfig.setFieldValue( - WifiEnterpriseConfig.ENGINE_KEY, (String) value); - break; - case XML_TAG_ENGINE_ID: - enterpriseConfig.setFieldValue( - WifiEnterpriseConfig.ENGINE_ID_KEY, (String) value); - break; - case XML_TAG_PRIVATE_KEY_ID: - enterpriseConfig.setFieldValue( - WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, (String) value); - break; - case XML_TAG_ALT_SUBJECT_MATCH: - enterpriseConfig.setFieldValue( - WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, (String) value); - break; - case XML_TAG_DOM_SUFFIX_MATCH: - enterpriseConfig.setFieldValue( - WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY, (String) value); - break; - case XML_TAG_CA_PATH: - enterpriseConfig.setFieldValue( - WifiEnterpriseConfig.CA_PATH_KEY, (String) value); - break; - case XML_TAG_EAP_METHOD: - enterpriseConfig.setEapMethod((int) value); - break; - case XML_TAG_PHASE2_METHOD: - enterpriseConfig.setPhase2Method((int) value); - break; - case XML_TAG_PLMN: - enterpriseConfig.setPlmn((String) value); - break; - case XML_TAG_REALM: - enterpriseConfig.setRealm((String) value); - break; - default: - throw new XmlPullParserException( - "Unknown value name found: " + valueName[0]); + while (XmlUtils.nextElementWithin(in, outerTagDepth)) { + if (in.getAttributeValue(null, "name") != null) { + // Value elements. + String[] valueName = new String[1]; + Object value = XmlUtil.readCurrentValue(in, valueName); + if (valueName[0] == null) { + throw new XmlPullParserException("Missing value name"); + } + switch (valueName[0]) { + case XML_TAG_IDENTITY: + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.IDENTITY_KEY, (String) value); + break; + case XML_TAG_ANON_IDENTITY: + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.ANON_IDENTITY_KEY, (String) value); + break; + case XML_TAG_PASSWORD: + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.PASSWORD_KEY, (String) value); + if (shouldExpectEncryptedCredentials + && !TextUtils.isEmpty(enterpriseConfig.getFieldValue( + WifiEnterpriseConfig.PASSWORD_KEY))) { + // Indicates that encryption of password failed when it was last + // written. + Log.e(TAG, "password value not expected"); + } + break; + case XML_TAG_CLIENT_CERT: + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.CLIENT_CERT_KEY, (String) value); + break; + case XML_TAG_CA_CERT: + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.CA_CERT_KEY, (String) value); + break; + case XML_TAG_SUBJECT_MATCH: + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.SUBJECT_MATCH_KEY, (String) value); + break; + case XML_TAG_ENGINE: + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.ENGINE_KEY, (String) value); + break; + case XML_TAG_ENGINE_ID: + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.ENGINE_ID_KEY, (String) value); + break; + case XML_TAG_PRIVATE_KEY_ID: + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, (String) value); + break; + case XML_TAG_ALT_SUBJECT_MATCH: + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, (String) value); + break; + case XML_TAG_DOM_SUFFIX_MATCH: + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY, (String) value); + break; + case XML_TAG_CA_PATH: + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.CA_PATH_KEY, (String) value); + break; + case XML_TAG_EAP_METHOD: + enterpriseConfig.setEapMethod((int) value); + break; + case XML_TAG_PHASE2_METHOD: + enterpriseConfig.setPhase2Method((int) value); + break; + case XML_TAG_PLMN: + enterpriseConfig.setPlmn((String) value); + break; + case XML_TAG_REALM: + enterpriseConfig.setRealm((String) value); + break; + default: + throw new XmlPullParserException( + "Unknown value name found: " + valueName[0]); + } + } else { + String tagName = in.getName(); + if (tagName == null) { + throw new XmlPullParserException("Unexpected null tag found"); + } + switch (tagName) { + case XML_TAG_PASSWORD: + if (!shouldExpectEncryptedCredentials) { + throw new XmlPullParserException( + "encrypted password section not expected"); + } + EncryptedData encryptedData = + EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1); + byte[] passwordBytes = encryptionUtil.decrypt(encryptedData); + if (passwordBytes == null) { + Log.wtf(TAG, "Decryption of password failed"); + } else { + enterpriseConfig.setFieldValue( + WifiEnterpriseConfig.PASSWORD_KEY, + new String(passwordBytes)); + } + break; + default: + throw new XmlPullParserException( + "Unknown tag name found: " + tagName); + } } } return enterpriseConfig; diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java index 9c16b1257..efa2d4336 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java @@ -16,8 +16,6 @@ package com.android.server.wifi; -import static com.android.server.wifi.WifiConfigStore.ZEROED_ENCRYPTED_DATA; - import static org.junit.Assert.*; import static org.mockito.Mockito.*; @@ -189,7 +187,7 @@ public class WifiConfigStoreTest { when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getNameForUid(anyInt())).thenReturn(TEST_CREATOR_NAME); when(mEncryptionUtil.encrypt(any(byte[].class))) - .thenReturn(ZEROED_ENCRYPTED_DATA); + .thenReturn(new EncryptedData(new byte[0], new byte[0])); when(mEncryptionUtil.decrypt(any(EncryptedData.class))) .thenReturn(new byte[0]); mSharedStore = new MockStoreFile(WifiConfigStore.STORE_FILE_SHARED_GENERAL); @@ -820,8 +818,8 @@ public class WifiConfigStoreTest { */ @Test public void testReadVersion2StoreFile() throws Exception { - byte[] encryptedData = new byte[EncryptedData.ENCRYPTED_DATA_LENGTH]; - byte[] iv = new byte[EncryptedData.IV_LENGTH]; + byte[] encryptedData = new byte[0]; + byte[] iv = new byte[0]; Random random = new Random(); random.nextBytes(encryptedData); random.nextBytes(iv); diff --git a/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java b/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java index 126a80d3c..66534d247 100644 --- a/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java +++ b/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java @@ -35,7 +35,11 @@ import com.android.server.wifi.util.XmlUtil.NetworkSelectionStatusXmlUtil; import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil; import com.android.server.wifi.util.XmlUtil.WifiEnterpriseConfigXmlUtil; +import org.junit.Before; import org.junit.Test; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; @@ -73,6 +77,13 @@ public class XmlUtilTest { private static final int TEST_PHASE2_METHOD = WifiEnterpriseConfig.Phase2.MSCHAPV2; private final String mXmlDocHeader = "XmlUtilTest"; + @Mock private WifiConfigStoreEncryptionUtil mWifiConfigStoreEncryptionUtil; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + } + /** * Verify that a open WifiConfiguration is serialized & deserialized correctly. */ @@ -101,6 +112,21 @@ public class XmlUtilTest { } /** + * Verify that a psk WifiConfiguration is serialized & deserialized correctly. + */ + @Test + public void testPskWifiConfigurationSerializeDeserializeWithEncryption() + throws IOException, XmlPullParserException { + WifiConfiguration pskNetwork = WifiConfigurationTestUtil.createPskNetwork(); + EncryptedData encryptedData = new EncryptedData(new byte[0], new byte[0]); + when(mWifiConfigStoreEncryptionUtil.encrypt(pskNetwork.preSharedKey.getBytes())) + .thenReturn(encryptedData); + when(mWifiConfigStoreEncryptionUtil.decrypt(encryptedData)) + .thenReturn(pskNetwork.preSharedKey.getBytes()); + serializeDeserializeWifiConfiguration(pskNetwork); + } + + /** * Verify that a psk hidden WifiConfiguration is serialized & deserialized correctly. */ @Test @@ -382,6 +408,36 @@ public class XmlUtilTest { } /** + * Verify that a WifiEnterpriseConfig object is serialized & deserialized correctly. + */ + @Test + public void testWifiEnterpriseConfigSerializeDeserializeWithEncryption() + throws IOException, XmlPullParserException { + WifiEnterpriseConfig config = new WifiEnterpriseConfig(); + config.setFieldValue(WifiEnterpriseConfig.IDENTITY_KEY, TEST_IDENTITY); + config.setFieldValue(WifiEnterpriseConfig.ANON_IDENTITY_KEY, TEST_ANON_IDENTITY); + config.setFieldValue(WifiEnterpriseConfig.PASSWORD_KEY, TEST_PASSWORD); + config.setFieldValue(WifiEnterpriseConfig.CLIENT_CERT_KEY, TEST_CLIENT_CERT); + config.setFieldValue(WifiEnterpriseConfig.CA_CERT_KEY, TEST_CA_CERT); + config.setFieldValue(WifiEnterpriseConfig.SUBJECT_MATCH_KEY, TEST_SUBJECT_MATCH); + config.setFieldValue(WifiEnterpriseConfig.ENGINE_KEY, TEST_ENGINE); + config.setFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY, TEST_ENGINE_ID); + config.setFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, TEST_PRIVATE_KEY_ID); + config.setFieldValue(WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, TEST_ALTSUBJECT_MATCH); + config.setFieldValue(WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY, TEST_DOM_SUFFIX_MATCH); + config.setFieldValue(WifiEnterpriseConfig.CA_PATH_KEY, TEST_CA_PATH); + config.setEapMethod(TEST_EAP_METHOD); + config.setPhase2Method(TEST_PHASE2_METHOD); + + EncryptedData encryptedData = new EncryptedData(new byte[0], new byte[0]); + when(mWifiConfigStoreEncryptionUtil.encrypt(TEST_PASSWORD.getBytes())) + .thenReturn(encryptedData); + when(mWifiConfigStoreEncryptionUtil.decrypt(encryptedData)) + .thenReturn(TEST_PASSWORD.getBytes()); + serializeDeserializeWifiEnterpriseConfig(config); + } + + /** * Verify that an illegal argument exception is thrown when trying to parse out a corrupted * WifiEnterpriseConfig. * @@ -474,7 +530,7 @@ public class XmlUtilTest { out.setOutput(outputStream, StandardCharsets.UTF_8.name()); XmlUtil.writeDocumentStart(out, mXmlDocHeader); WifiConfigurationXmlUtil.writeToXmlForConfigStore( - out, configuration, mock(WifiConfigStoreEncryptionUtil.class)); + out, configuration, mWifiConfigStoreEncryptionUtil); XmlUtil.writeDocumentEnd(out, mXmlDocHeader); return outputStream.toByteArray(); } @@ -487,7 +543,9 @@ public class XmlUtilTest { in.setInput(inputStream, StandardCharsets.UTF_8.name()); XmlUtil.gotoDocumentStart(in, mXmlDocHeader); return WifiConfigurationXmlUtil.parseFromXml( - in, in.getDepth(), false, mock(WifiConfigStoreEncryptionUtil.class)); + in, in.getDepth(), + mWifiConfigStoreEncryptionUtil != null, + mWifiConfigStoreEncryptionUtil); } /** @@ -596,7 +654,7 @@ public class XmlUtilTest { out.setOutput(outputStream, StandardCharsets.UTF_8.name()); XmlUtil.writeDocumentStart(out, mXmlDocHeader); WifiEnterpriseConfigXmlUtil.writeToXml( - out, config, mock(WifiConfigStoreEncryptionUtil.class)); + out, config, mWifiConfigStoreEncryptionUtil); XmlUtil.writeDocumentEnd(out, mXmlDocHeader); return outputStream.toByteArray(); } @@ -608,7 +666,8 @@ public class XmlUtilTest { in.setInput(inputStream, StandardCharsets.UTF_8.name()); XmlUtil.gotoDocumentStart(in, mXmlDocHeader); return WifiEnterpriseConfigXmlUtil.parseFromXml( - in, in.getDepth(), false, mock(WifiConfigStoreEncryptionUtil.class)); + in, in.getDepth(), mWifiConfigStoreEncryptionUtil != null, + mWifiConfigStoreEncryptionUtil); } private void serializeDeserializeWifiEnterpriseConfig(WifiEnterpriseConfig config) |