From a161d62d9baac95a087cb3252d51c1fd101d24fa Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Tue, 22 Oct 2019 13:42:45 -0700 Subject: WifiConfigStore: Encrypt credentials for networks (1/4) Changes in the CL: a) Introduced a new config store version. The new version gets rid of the integrity computation & adds support for encryption of credential data. b) Changed DataIntegrityChecker to WifiConfigStoreEncryptionUtil to help the different config store modules to encrypt/decrypt their credential data to be stored. c) Pass the version & the new EncryptionUtil to all the config store modules. The version is needed for the modules to handle upgrades. d) Use the WIFI_UID to store encryption key in keystore (to help ease migrate keys if we move to a separate process in R) Actual encryption of credential data/handling of upgrades will be added in the next CL. Bug: 140485110 Test: atest com.android.server.wifi Change-Id: I522b11ef2ffbdbf0ff19ae4f2643023df3843e5e Merged-In: I522b11ef2ffbdbf0ff19ae4f2643023df3843e5e --- .../wifi/DeletedEphemeralSsidsStoreData.java | 10 +- .../android/server/wifi/NetworkListStoreData.java | 9 +- .../server/wifi/NetworkRequestStoreData.java | 9 +- .../server/wifi/NetworkSuggestionStoreData.java | 9 +- .../server/wifi/RandomizedMacStoreData.java | 10 +- .../com/android/server/wifi/SsidSetStoreData.java | 9 +- .../android/server/wifi/WakeupConfigStoreData.java | 9 +- .../com/android/server/wifi/WifiConfigStore.java | 209 +++++---------- .../hotspot2/PasspointConfigSharedStoreData.java | 10 +- .../hotspot2/PasspointConfigUserStoreData.java | 9 +- .../server/wifi/util/DataIntegrityChecker.java | 278 ------------------- .../wifi/util/WifiConfigStoreEncryptionUtil.java | 193 ++++++++++++++ .../wifi/DeletedEphemeralSsidsStoreDataTest.java | 8 +- .../server/wifi/NetworkListStoreDataTest.java | 7 +- .../server/wifi/NetworkRequestStoreDataTest.java | 7 +- .../wifi/NetworkSuggestionStoreDataTest.java | 7 +- .../server/wifi/RandomizedMacStoreDataTest.java | 7 +- .../android/server/wifi/SsidSetStoreDataTest.java | 8 +- .../server/wifi/WakeupConfigStoreDataTest.java | 12 +- .../android/server/wifi/WakeupControllerTest.java | 6 +- .../android/server/wifi/WifiConfigStoreTest.java | 294 ++++----------------- .../server/wifi/WifiNetworkFactoryTest.java | 7 +- .../PasspointConfigSharedStoreDataTest.java | 7 +- .../hotspot2/PasspointConfigUserStoreDataTest.java | 7 +- .../server/wifi/util/DataIntegrityCheckerTest.java | 69 ----- 25 files changed, 429 insertions(+), 781 deletions(-) delete mode 100644 service/java/com/android/server/wifi/util/DataIntegrityChecker.java create mode 100644 service/java/com/android/server/wifi/util/WifiConfigStoreEncryptionUtil.java delete mode 100644 tests/wifitests/src/com/android/server/wifi/util/DataIntegrityCheckerTest.java diff --git a/service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java b/service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java index 0c064884c..3575ff254 100644 --- a/service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java +++ b/service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java @@ -16,6 +16,9 @@ package com.android.server.wifi; +import android.annotation.NonNull; + +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; import org.xmlpull.v1.XmlPullParser; @@ -44,7 +47,8 @@ public class DeletedEphemeralSsidsStoreData implements WifiConfigStore.StoreData } @Override - public void serializeData(XmlSerializer out) + public void serializeData(XmlSerializer out, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { if (mSsidToTimeMap != null) { XmlUtil.writeNextValue(out, XML_TAG_SSID_LIST, mSsidToTimeMap); @@ -52,7 +56,9 @@ public class DeletedEphemeralSsidsStoreData implements WifiConfigStore.StoreData } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth) + public void deserializeData(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/NetworkListStoreData.java b/service/java/com/android/server/wifi/NetworkListStoreData.java index 696647185..981e97c7e 100644 --- a/service/java/com/android/server/wifi/NetworkListStoreData.java +++ b/service/java/com/android/server/wifi/NetworkListStoreData.java @@ -16,6 +16,7 @@ package com.android.server.wifi; +import android.annotation.NonNull; import android.content.Context; import android.net.IpConfiguration; import android.net.wifi.WifiConfiguration; @@ -25,6 +26,7 @@ import android.os.Process; import android.util.Log; import android.util.Pair; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; import com.android.server.wifi.util.XmlUtil.IpConfigurationXmlUtil; import com.android.server.wifi.util.XmlUtil.NetworkSelectionStatusXmlUtil; @@ -66,13 +68,16 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData } @Override - public void serializeData(XmlSerializer out) + public void serializeData(XmlSerializer out, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { serializeNetworkList(out, mConfigurations); } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth) + public void deserializeData(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/NetworkRequestStoreData.java b/service/java/com/android/server/wifi/NetworkRequestStoreData.java index 8d1244f05..3a5143f56 100644 --- a/service/java/com/android/server/wifi/NetworkRequestStoreData.java +++ b/service/java/com/android/server/wifi/NetworkRequestStoreData.java @@ -16,10 +16,12 @@ package com.android.server.wifi; +import android.annotation.NonNull; import android.net.MacAddress; import android.util.Log; import com.android.server.wifi.WifiNetworkFactory.AccessPoint; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil; @@ -87,13 +89,16 @@ public class NetworkRequestStoreData implements WifiConfigStore.StoreData { } @Override - public void serializeData(XmlSerializer out) + public void serializeData(XmlSerializer out, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { serializeApprovedAccessPointsMap(out, mDataSource.toSerialize()); } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth) + public void deserializeData(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java b/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java index 9627a9daa..e9503b7e4 100644 --- a/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java +++ b/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java @@ -16,6 +16,7 @@ package com.android.server.wifi; +import android.annotation.NonNull; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; import android.net.wifi.WifiNetworkSuggestion; @@ -26,6 +27,7 @@ import android.util.Pair; import com.android.internal.util.XmlUtils; import com.android.server.wifi.WifiNetworkSuggestionsManager.ExtendedWifiNetworkSuggestion; import com.android.server.wifi.WifiNetworkSuggestionsManager.PerAppInfo; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil; @@ -98,13 +100,16 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { } @Override - public void serializeData(XmlSerializer out) + public void serializeData(XmlSerializer out, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { serializeNetworkSuggestionsMap(out, mDataSource.toSerialize()); } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth) + public void deserializeData(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/RandomizedMacStoreData.java b/service/java/com/android/server/wifi/RandomizedMacStoreData.java index 1e4d972ef..8e47ee7bf 100644 --- a/service/java/com/android/server/wifi/RandomizedMacStoreData.java +++ b/service/java/com/android/server/wifi/RandomizedMacStoreData.java @@ -16,6 +16,9 @@ package com.android.server.wifi; +import android.annotation.NonNull; + +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; import org.xmlpull.v1.XmlPullParser; @@ -40,7 +43,8 @@ public class RandomizedMacStoreData implements WifiConfigStore.StoreData { RandomizedMacStoreData() {} @Override - public void serializeData(XmlSerializer out) + public void serializeData(XmlSerializer out, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { if (mMacMapping != null) { XmlUtil.writeNextValue(out, XML_TAG_MAC_MAP, mMacMapping); @@ -48,7 +52,9 @@ public class RandomizedMacStoreData implements WifiConfigStore.StoreData { } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth) + public void deserializeData(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/SsidSetStoreData.java b/service/java/com/android/server/wifi/SsidSetStoreData.java index 7d1b99340..1339dae38 100644 --- a/service/java/com/android/server/wifi/SsidSetStoreData.java +++ b/service/java/com/android/server/wifi/SsidSetStoreData.java @@ -16,8 +16,10 @@ package com.android.server.wifi; +import android.annotation.NonNull; import android.text.TextUtils; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; import org.xmlpull.v1.XmlPullParser; @@ -74,7 +76,8 @@ public class SsidSetStoreData implements WifiConfigStore.StoreData { } @Override - public void serializeData(XmlSerializer out) + public void serializeData(XmlSerializer out, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { Set ssidSet = mDataSource.getSsids(); if (ssidSet != null && !ssidSet.isEmpty()) { @@ -83,7 +86,9 @@ public class SsidSetStoreData implements WifiConfigStore.StoreData { } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth) + public void deserializeData(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/WakeupConfigStoreData.java b/service/java/com/android/server/wifi/WakeupConfigStoreData.java index d191ee3d6..1d146a0e1 100644 --- a/service/java/com/android/server/wifi/WakeupConfigStoreData.java +++ b/service/java/com/android/server/wifi/WakeupConfigStoreData.java @@ -16,10 +16,12 @@ package com.android.server.wifi; +import android.annotation.NonNull; import android.util.ArraySet; import android.util.Log; import com.android.server.wifi.WifiConfigStore.StoreData; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; import org.xmlpull.v1.XmlPullParser; @@ -94,7 +96,8 @@ public class WakeupConfigStoreData implements StoreData { } @Override - public void serializeData(XmlSerializer out) + public void serializeData(XmlSerializer out, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { writeFeatureState(out); @@ -141,7 +144,9 @@ public class WakeupConfigStoreData implements StoreData { } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth) + public void deserializeData(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { if (!mHasBeenRead) { Log.d(TAG, "WifiWake user data has been read"); diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index e189d00e1..efe4a4c8d 100644 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -35,8 +35,8 @@ import com.android.internal.annotations.VisibleForTesting; import com.android.internal.os.AtomicFile; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.Preconditions; -import com.android.server.wifi.util.DataIntegrityChecker; import com.android.server.wifi.util.EncryptedData; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; import org.xmlpull.v1.XmlPullParser; @@ -53,7 +53,6 @@ import java.io.IOException; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; -import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; @@ -106,17 +105,33 @@ public class WifiConfigStore { /** * Current config store data version. This will be incremented for any additions. */ - private static final int CURRENT_CONFIG_STORE_DATA_VERSION = 2; + private static final int CURRENT_CONFIG_STORE_DATA_VERSION = 3; /** This list of older versions will be used to restore data from older config store. */ /** * First version of the config store data format. */ - private static final int INITIAL_CONFIG_STORE_DATA_VERSION = 1; + public static final int INITIAL_CONFIG_STORE_DATA_VERSION = 1; /** * Second version of the config store data format, introduced: * - Integrity info. */ - private static final int INTEGRITY_CONFIG_STORE_DATA_VERSION = 2; + public static final int INTEGRITY_CONFIG_STORE_DATA_VERSION = 2; + /** + * Third version of the config store data format, + * introduced: + * - Encryption of credentials + * removed: + * - Integrity info. + */ + public static final int ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION = 3; + + @IntDef(suffix = { "_VERSION" }, value = { + INITIAL_CONFIG_STORE_DATA_VERSION, + INTEGRITY_CONFIG_STORE_DATA_VERSION, + ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Version { } /** * Alarm tag to use for starting alarms for buffering file writes. @@ -291,8 +306,9 @@ public class WifiConfigStore { } } File file = new File(storeDir, STORE_ID_TO_FILE_NAME.get(fileId)); - DataIntegrityChecker dataIntegrityChecker = new DataIntegrityChecker(file.getName()); - return new StoreFile(file, fileId, dataIntegrityChecker); + WifiConfigStoreEncryptionUtil encryptionUtil = + new WifiConfigStoreEncryptionUtil(file.getName()); + return new StoreFile(file, fileId, encryptionUtil); } /** @@ -427,88 +443,18 @@ public class WifiConfigStore { final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - // To compute integrity, write zeroes in the integrity fields. Once the integrity is - // computed, go back and modfiy the XML fields in place with the computed values. - writeDocumentMetadata(out, ZEROED_ENCRYPTED_DATA); + // First XML header. + XmlUtil.writeDocumentStart(out, XML_TAG_DOCUMENT_HEADER); + // Next version. + XmlUtil.writeNextValue(out, XML_TAG_VERSION, CURRENT_CONFIG_STORE_DATA_VERSION); for (StoreData storeData : storeDataList) { String tag = storeData.getName(); XmlUtil.writeNextSectionStart(out, tag); - storeData.serializeData(out); + storeData.serializeData(out, storeFile.getEncryptionUtil()); XmlUtil.writeNextSectionEnd(out, tag); } XmlUtil.writeDocumentEnd(out, XML_TAG_DOCUMENT_HEADER); - - byte[] outBytes = outputStream.toByteArray(); - EncryptedData encryptedData = storeFile.computeIntegrity(outBytes); - if (encryptedData == null) { - // should never happen, this is a fatal failure. Abort file write. - Log.wtf(TAG, "Failed to compute integrity, failing write"); - return null; - } - return rewriteDocumentMetadataRawBytes(outBytes, encryptedData); - } - - /** - * Helper method to write the metadata at the start of every config store file. - * The metadata consists of: - * a) Version - * b) Integrity data computed on the data contents. - */ - private void writeDocumentMetadata(XmlSerializer out, EncryptedData encryptedData) - throws XmlPullParserException, IOException { - // First XML header. - XmlUtil.writeDocumentStart(out, XML_TAG_DOCUMENT_HEADER); - // Next version. - XmlUtil.writeNextValue(out, XML_TAG_VERSION, CURRENT_CONFIG_STORE_DATA_VERSION); - - // Next integrity data. - XmlUtil.writeNextSectionStart(out, XML_TAG_HEADER_INTEGRITY); - XmlUtil.writeNextValue(out, XML_TAG_INTEGRITY_ENCRYPTED_DATA, - encryptedData.getEncryptedData()); - XmlUtil.writeNextValue(out, XML_TAG_INTEGRITY_IV, encryptedData.getIv()); - XmlUtil.writeNextSectionEnd(out, XML_TAG_HEADER_INTEGRITY); - } - - /** - * Helper method to generate the raw bytes containing the the metadata at the start of every - * config store file. - * - * NOTE: This does not create a fully formed XML document (the start tag is not closed for - * example). This only creates the top portion of the XML which contains the modified - * integrity data & version along with the XML prolog (metadata): - * - * - * - * - * !EncryptedData! - * !IV! - * - */ - private byte[] generateDocumentMetadataRawBytes(EncryptedData encryptedData) - throws XmlPullParserException, IOException { - final XmlSerializer outXml = new FastXmlSerializer(); - final ByteArrayOutputStream outStream = new ByteArrayOutputStream(); - outXml.setOutput(outStream, StandardCharsets.UTF_8.name()); - writeDocumentMetadata(outXml, encryptedData); - outXml.endDocument(); - return outStream.toByteArray(); - } - - /** - * Helper method to rewrite the existing document metadata in the incoming raw bytes in - * |inBytes| with the new document metadata created with the provided |encryptedData|. - * - * NOTE: This assumes that the metadata in existing XML inside |inBytes| aligns exactly - * with the new metadata created. So, a simple in place rewrite of the first few bytes ( - * corresponding to metadata section of the document) from |inBytes| will preserve the overall - * document structure. - */ - private byte[] rewriteDocumentMetadataRawBytes(byte[] inBytes, EncryptedData encryptedData) - throws XmlPullParserException, IOException { - byte[] replaceMetadataBytes = generateDocumentMetadataRawBytes(encryptedData); - ByteBuffer outByteBuffer = ByteBuffer.wrap(inBytes); - outByteBuffer.put(replaceMetadataBytes); - return outByteBuffer.array(); + return outputStream.toByteArray(); } /** @@ -629,10 +575,11 @@ public class WifiConfigStore { } // Inform all the provided store data clients that there is nothing in the store for them. - private void indicateNoDataForStoreDatas(Collection storeDataSet) + private void indicateNoDataForStoreDatas(Collection storeDataSet, + @Version int version, @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { for (StoreData storeData : storeDataSet) { - storeData.deserializeData(null, 0); + storeData.deserializeData(null, 0, version, encryptionUtil); } } @@ -654,7 +601,8 @@ public class WifiConfigStore { throws XmlPullParserException, IOException { List storeDataList = retrieveStoreDataListForStoreFile(storeFile); if (dataBytes == null) { - indicateNoDataForStoreDatas(storeDataList); + indicateNoDataForStoreDatas(storeDataList, -1 /* unknown */, + storeFile.getEncryptionUtil()); return; } final XmlPullParser in = Xml.newPullParser(); @@ -665,21 +613,10 @@ public class WifiConfigStore { int rootTagDepth = in.getDepth() + 1; XmlUtil.gotoDocumentStart(in, XML_TAG_DOCUMENT_HEADER); - int version = parseVersionFromXml(in); - // Version 2 onwards contains integrity data, so check the integrity of the file. - if (version >= INTEGRITY_CONFIG_STORE_DATA_VERSION) { - EncryptedData integrityData = parseIntegrityDataFromXml(in, rootTagDepth); - // To compute integrity, write zeroes in the integrity fields. - dataBytes = rewriteDocumentMetadataRawBytes(dataBytes, ZEROED_ENCRYPTED_DATA); - if (!storeFile.checkIntegrity(dataBytes, integrityData)) { - Log.wtf(TAG, "Integrity mismatch, discarding data from " + storeFile.mFileName); - return; - } - } else { - // When integrity checking is introduced. The existing data will have no related - // integrity file for validation. Thus, we will assume the existing data is correct. - // Integrity will be computed for the next write. - Log.d(TAG, "No integrity data to check; thus vacously true"); + @Version int version = parseVersionFromXml(in); + // Version 2 contains the now unused integrity data, parse & then discard the information. + if (version == INTEGRITY_CONFIG_STORE_DATA_VERSION) { + parseAndDiscardIntegrityDataFromXml(in, rootTagDepth); } String[] headerName = new String[1]; @@ -695,14 +632,15 @@ public class WifiConfigStore { throw new XmlPullParserException("Unknown store data: " + headerName[0] + ". List of store data: " + storeDataList); } - storeData.deserializeData(in, rootTagDepth + 1); + storeData.deserializeData(in, rootTagDepth + 1, version, + storeFile.getEncryptionUtil()); storeDatasInvoked.add(storeData); } // Inform all the other registered store data clients that there is nothing in the store // for them. Set storeDatasNotInvoked = new HashSet<>(storeDataList); storeDatasNotInvoked.removeAll(storeDatasInvoked); - indicateNoDataForStoreDatas(storeDatasNotInvoked); + indicateNoDataForStoreDatas(storeDatasNotInvoked, version, storeFile.getEncryptionUtil()); } /** @@ -712,7 +650,7 @@ public class WifiConfigStore { * @param in XmlPullParser instance pointing to the XML stream. * @return version number retrieved from the Xml stream. */ - private static int parseVersionFromXml(XmlPullParser in) + private static @Version int parseVersionFromXml(XmlPullParser in) throws XmlPullParserException, IOException { int version = (int) XmlUtil.readNextValueWithName(in, XML_TAG_VERSION); if (version < INITIAL_CONFIG_STORE_DATA_VERSION @@ -723,22 +661,16 @@ public class WifiConfigStore { } /** - * Parse the integrity data structure from the XML stream. - * This is used for both the shared and user config store data. + * Parse the integrity data structure from the XML stream and discard it. * * @param in XmlPullParser instance pointing to the XML stream. * @param outerTagDepth Outer tag depth. - * @return Instance of {@link EncryptedData} retrieved from the Xml stream. */ - private static @NonNull EncryptedData parseIntegrityDataFromXml( - XmlPullParser in, int outerTagDepth) + private static void parseAndDiscardIntegrityDataFromXml(XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException { XmlUtil.gotoNextSectionWithName(in, XML_TAG_HEADER_INTEGRITY, outerTagDepth); - byte[] encryptedData = - (byte[]) XmlUtil.readNextValueWithName(in, XML_TAG_INTEGRITY_ENCRYPTED_DATA); - byte[] iv = - (byte[]) XmlUtil.readNextValueWithName(in, XML_TAG_INTEGRITY_IV); - return new EncryptedData(encryptedData, iv); + XmlUtil.readNextValueWithName(in, XML_TAG_INTEGRITY_ENCRYPTED_DATA); + XmlUtil.readNextValueWithName(in, XML_TAG_INTEGRITY_IV); } /** @@ -790,14 +722,14 @@ public class WifiConfigStore { /** * Integrity checking for the store file. */ - private final DataIntegrityChecker mDataIntegrityChecker; + private final WifiConfigStoreEncryptionUtil mEncryptionUtil; public StoreFile(File file, @StoreFileId int fileId, - @NonNull DataIntegrityChecker dataIntegrityChecker) { + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) { mAtomicFile = new AtomicFile(file); mFileName = file.getAbsolutePath(); mFileId = fileId; - mDataIntegrityChecker = dataIntegrityChecker; + mEncryptionUtil = encryptionUtil; } /** @@ -809,6 +741,13 @@ public class WifiConfigStore { return mAtomicFile.exists(); } + /** + * @return Returns the encryption util used for this store file. + */ + public @NonNull WifiConfigStoreEncryptionUtil getEncryptionUtil() { + return mEncryptionUtil; + } + /** * Read the entire raw data from the store file and return in a byte array. * @@ -862,33 +801,6 @@ public class WifiConfigStore { // Reset the pending write data after write. mWriteData = null; } - - /** - * Compute integrity of |dataWithZeroedIntegrityFields| to be written to the file. - * - * @param dataWithZeroedIntegrityFields raw data to be written to the file with the - * integrity fields zeroed out for integrity - * calculation. - * @return Instance of {@link EncryptedData} holding the encrypted integrity data for the - * raw data to be written to the file. - */ - public EncryptedData computeIntegrity(byte[] dataWithZeroedIntegrityFields) { - return mDataIntegrityChecker.compute(dataWithZeroedIntegrityFields); - } - - /** - * Check integrity of |dataWithZeroedIntegrityFields| read from the file with the integrity - * data parsed from the file. - * @param dataWithZeroedIntegrityFields raw data read from the file with the integrity - * fields zeroed out for integrity calculation. - * @param parsedEncryptedData Instance of {@link EncryptedData} parsed from the integrity - * fields in the raw data. - * @return true if the integrity matches, false otherwise. - */ - public boolean checkIntegrity(byte[] dataWithZeroedIntegrityFields, - EncryptedData parsedEncryptedData) { - return mDataIntegrityChecker.isOk(dataWithZeroedIntegrityFields, parsedEncryptedData); - } } /** @@ -908,8 +820,9 @@ public class WifiConfigStore { * Serialize a XML data block to the output stream. * * @param out The output stream to serialize the data to + * @param encryptionUtil Utility to help encrypt any credential data. */ - void serializeData(XmlSerializer out) + void serializeData(XmlSerializer out, @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException; /** @@ -918,10 +831,14 @@ public class WifiConfigStore { * @param in The input stream to read the data from. This could be null if there is * nothing in the store. * @param outerTagDepth The depth of the outer tag in the XML document + * @param version Version of config store file. + * @param encryptionUtil Utility to help decrypt any credential data. + * * Note: This will be invoked every time a store file is read, even if there is nothing * in the store for them. */ - void deserializeData(@Nullable XmlPullParser in, int outerTagDepth) + void deserializeData(@Nullable XmlPullParser in, int outerTagDepth, @Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException; /** diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreData.java b/service/java/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreData.java index 419ea7993..9abccb94b 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreData.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreData.java @@ -16,7 +16,10 @@ package com.android.server.wifi.hotspot2; +import android.annotation.NonNull; + import com.android.server.wifi.WifiConfigStore; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; import org.xmlpull.v1.XmlPullParser; @@ -72,13 +75,16 @@ public class PasspointConfigSharedStoreData implements WifiConfigStore.StoreData } @Override - public void serializeData(XmlSerializer out) + public void serializeData(XmlSerializer out, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { serializeShareData(out); } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth) + public void deserializeData(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java b/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java index 0114cfb21..1001b1189 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java @@ -16,6 +16,7 @@ package com.android.server.wifi.hotspot2; +import android.annotation.NonNull; import android.net.wifi.hotspot2.PasspointConfiguration; import android.text.TextUtils; @@ -23,6 +24,7 @@ import com.android.internal.util.XmlUtils; import com.android.server.wifi.SIMAccessor; import com.android.server.wifi.WifiConfigStore; import com.android.server.wifi.WifiKeyStore; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; import org.xmlpull.v1.XmlPullParser; @@ -103,13 +105,16 @@ public class PasspointConfigUserStoreData implements WifiConfigStore.StoreData { } @Override - public void serializeData(XmlSerializer out) + public void serializeData(XmlSerializer out, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { serializeUserData(out); } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth) + public void deserializeData(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/util/DataIntegrityChecker.java b/service/java/com/android/server/wifi/util/DataIntegrityChecker.java deleted file mode 100644 index 6f03a4861..000000000 --- a/service/java/com/android/server/wifi/util/DataIntegrityChecker.java +++ /dev/null @@ -1,278 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wifi.util; - -import android.annotation.NonNull; -import android.os.SystemProperties; -import android.security.keystore.KeyGenParameterSpec; -import android.security.keystore.KeyProperties; -import android.text.TextUtils; -import android.util.Log; - -import java.io.IOException; -import java.security.InvalidAlgorithmParameterException; -import java.security.InvalidKeyException; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; -import java.security.NoSuchProviderException; -import java.security.UnrecoverableEntryException; -import java.security.cert.CertificateException; - -import javax.crypto.BadPaddingException; -import javax.crypto.Cipher; -import javax.crypto.IllegalBlockSizeException; -import javax.crypto.KeyGenerator; -import javax.crypto.NoSuchPaddingException; -import javax.crypto.SecretKey; -import javax.crypto.spec.GCMParameterSpec; - -/** - * Tools to provide integrity checking of byte arrays based on NIAP Common Criteria Protection - * Profile FCS_STG_EXT.3.1. - */ -public class DataIntegrityChecker { - private static final String TAG = "DataIntegrityChecker"; - - private static final String ALIAS_SUFFIX = ".data-integrity-checker-key"; - private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding"; - private static final String DIGEST_ALGORITHM = "SHA-256"; - private static final int GCM_TAG_LENGTH = 128; - private static final String KEY_STORE = "AndroidKeyStore"; - - /** - * When KEYSTORE_FAILURE_RETURN_VALUE is true, all cryptographic operation failures will not - * enforce security and {@link #isOk(byte[], EncryptedData)} always return true. - */ - private static final boolean KEYSTORE_FAILURE_RETURN_VALUE = true; - - private final String mDataFileName; - - /** - * Construct a new integrity checker to update and check if/when a data file was altered - * outside expected conditions. - * - * @param dataFileName The full path of the data file for which integrity check is performed. - * @throws NullPointerException When data file is empty string. - */ - public DataIntegrityChecker(@NonNull String dataFileName) { - if (TextUtils.isEmpty(dataFileName)) { - throw new NullPointerException("dataFileName must not be null or the empty " - + "string"); - } - mDataFileName = dataFileName; - } - - private String getKeyAlias() { - return mDataFileName + ALIAS_SUFFIX; - } - - /** - * Computes a digest of a byte array, encrypt it, and store the result - * - * Call this method immediately before storing the byte array - * - * @param data The data desired to ensure integrity - * @return Instance of {@link EncryptedData} containing the encrypted integrity data. - */ - public EncryptedData compute(byte[] data) { - if (data == null || data.length < 1) { - reportException(new Exception("No data to compute"), "No data to compute."); - return null; - } - byte[] digest = getDigest(data); - if (digest == null || digest.length < 1) { - reportException(new Exception("digest null in compute"), - "digest null in compute"); - return null; - } - EncryptedData integrityData = encrypt(digest, getKeyAlias()); - if (integrityData == null) { - reportException(new Exception("integrityData null in compute"), - "integrityData null in compute"); - } - return integrityData; - } - - - /** - * Check the integrity of a given byte array - * - * Call this method immediately before trusting the byte array. This method will return false - * when the integrity data calculated on the byte array does not match the encrypted integrity - * data provided to compare or if there is an underlying issue with the cryptographic functions - * or the key store. - * - * @param data The data to check if its been altered. - * @param integrityData Encrypted integrity data to be used for comparison. - * @return true if the integrity data computed on |data| matches the provided |integrityData|. - */ - public boolean isOk(@NonNull byte[] data, @NonNull EncryptedData integrityData) { - if (data == null || data.length < 1) { - return KEYSTORE_FAILURE_RETURN_VALUE; - } - byte[] currentDigest = getDigest(data); - if (currentDigest == null || currentDigest.length < 1) { - reportException(new Exception("current digest null"), "current digest null"); - return KEYSTORE_FAILURE_RETURN_VALUE; - } - if (integrityData == null) { - reportException(new Exception("integrityData null in isOk"), - "integrityData null in isOk"); - return KEYSTORE_FAILURE_RETURN_VALUE; - } - byte[] storedDigest = decrypt(integrityData, getKeyAlias()); - if (storedDigest == null) { - return KEYSTORE_FAILURE_RETURN_VALUE; - } - return constantTimeEquals(storedDigest, currentDigest); - } - - private byte[] getDigest(byte[] data) { - try { - return MessageDigest.getInstance(DIGEST_ALGORITHM).digest(data); - } catch (NoSuchAlgorithmException e) { - reportException(e, "getDigest could not find algorithm: " + DIGEST_ALGORITHM); - return null; - } - } - - private EncryptedData encrypt(byte[] data, String keyAlias) { - EncryptedData encryptedData = null; - try { - Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); - SecretKey secretKeyReference = getOrCreateSecretKey(keyAlias); - if (secretKeyReference != null) { - cipher.init(Cipher.ENCRYPT_MODE, secretKeyReference); - encryptedData = new EncryptedData(cipher.doFinal(data), cipher.getIV()); - } else { - reportException(new Exception("secretKeyReference is null."), - "secretKeyReference is null."); - } - } catch (NoSuchAlgorithmException e) { - reportException(e, "encrypt could not find the algorithm: " + CIPHER_ALGORITHM); - } catch (NoSuchPaddingException e) { - reportException(e, "encrypt had a padding exception"); - } catch (InvalidKeyException e) { - reportException(e, "encrypt received an invalid key"); - } catch (BadPaddingException e) { - reportException(e, "encrypt had a padding problem"); - } catch (IllegalBlockSizeException e) { - reportException(e, "encrypt had an illegal block size"); - } - return encryptedData; - } - - private byte[] decrypt(EncryptedData encryptedData, String keyAlias) { - byte[] decryptedData = null; - try { - Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); - GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, encryptedData.getIv()); - SecretKey secretKeyReference = getOrCreateSecretKey(keyAlias); - if (secretKeyReference != null) { - cipher.init(Cipher.DECRYPT_MODE, secretKeyReference, spec); - decryptedData = cipher.doFinal(encryptedData.getEncryptedData()); - } - } catch (NoSuchAlgorithmException e) { - reportException(e, "decrypt could not find cipher algorithm " + CIPHER_ALGORITHM); - } catch (NoSuchPaddingException e) { - reportException(e, "decrypt could not find padding algorithm"); - } catch (IllegalBlockSizeException e) { - reportException(e, "decrypt had a illegal block size"); - } catch (BadPaddingException e) { - reportException(e, "decrypt had bad padding"); - } catch (InvalidKeyException e) { - reportException(e, "decrypt had an invalid key"); - } catch (InvalidAlgorithmParameterException e) { - reportException(e, "decrypt had an invalid algorithm parameter"); - } - return decryptedData; - } - - private SecretKey getOrCreateSecretKey(String keyAlias) { - SecretKey secretKey = null; - try { - KeyStore keyStore = KeyStore.getInstance(KEY_STORE); - keyStore.load(null); - if (keyStore.containsAlias(keyAlias)) { // The key exists in key store. Get the key. - KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore - .getEntry(keyAlias, null); - if (secretKeyEntry != null) { - secretKey = secretKeyEntry.getSecretKey(); - } else { - reportException(new Exception("keystore contains the alias and the secret key " - + "entry was null"), - "keystore contains the alias and the secret key entry was null"); - } - } else { // The key does not exist in key store. Create the key and store it. - KeyGenerator keyGenerator = KeyGenerator - .getInstance(KeyProperties.KEY_ALGORITHM_AES, KEY_STORE); - - KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(keyAlias, - KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) - .setBlockModes(KeyProperties.BLOCK_MODE_GCM) - .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) - .build(); - - keyGenerator.init(keyGenParameterSpec); - secretKey = keyGenerator.generateKey(); - } - } catch (CertificateException e) { - reportException(e, "getOrCreateSecretKey had a certificate exception."); - } catch (InvalidAlgorithmParameterException e) { - reportException(e, "getOrCreateSecretKey had an invalid algorithm parameter"); - } catch (IOException e) { - reportException(e, "getOrCreateSecretKey had an IO exception."); - } catch (KeyStoreException e) { - reportException(e, "getOrCreateSecretKey cannot find the keystore: " + KEY_STORE); - } catch (NoSuchAlgorithmException e) { - reportException(e, "getOrCreateSecretKey cannot find algorithm"); - } catch (NoSuchProviderException e) { - reportException(e, "getOrCreateSecretKey cannot find crypto provider"); - } catch (UnrecoverableEntryException e) { - reportException(e, "getOrCreateSecretKey had an unrecoverable entry exception."); - } - return secretKey; - } - - private boolean constantTimeEquals(byte[] a, byte[] b) { - if (a == null && b == null) { - return true; - } - - if (a == null || b == null || a.length != b.length) { - return false; - } - - byte differenceAccumulator = 0; - for (int i = 0; i < a.length; ++i) { - differenceAccumulator |= a[i] ^ b[i]; - } - return (differenceAccumulator == 0); - } - - /* TODO(b/128526030): Remove this error reporting code upon resolving the bug. */ - private static final boolean REQUEST_BUG_REPORT = false; - private void reportException(Exception exception, String error) { - Log.wtf(TAG, "An irrecoverable key store error was encountered: " + error, exception); - if (REQUEST_BUG_REPORT) { - SystemProperties.set("dumpstate.options", "bugreportwifi"); - SystemProperties.set("ctl.start", "bugreport"); - } - } -} diff --git a/service/java/com/android/server/wifi/util/WifiConfigStoreEncryptionUtil.java b/service/java/com/android/server/wifi/util/WifiConfigStoreEncryptionUtil.java new file mode 100644 index 000000000..2f9b08f2b --- /dev/null +++ b/service/java/com/android/server/wifi/util/WifiConfigStoreEncryptionUtil.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.os.Process; +import android.os.SystemProperties; +import android.security.keystore.AndroidKeyStoreProvider; +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.KeyProperties; +import android.text.TextUtils; +import android.util.Log; + +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.KeyStore; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.NoSuchProviderException; +import java.security.UnrecoverableEntryException; + +import javax.crypto.BadPaddingException; +import javax.crypto.Cipher; +import javax.crypto.IllegalBlockSizeException; +import javax.crypto.KeyGenerator; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; + +/** + * Tools to help encrypt/decrypt + */ +public class WifiConfigStoreEncryptionUtil { + private static final String TAG = "WifiConfigStoreEncryptionUtil"; + + private static final String ALIAS_SUFFIX = ".data-encryption-key"; + private static final String CIPHER_ALGORITHM = "AES/GCM/NoPadding"; + private static final int GCM_TAG_LENGTH = 128; + private static final String KEY_STORE = "AndroidKeyStore"; + + private final String mDataFileName; + + /** + * Construct a new util to help {@link com.android.server.wifi.WifiConfigStore.StoreData} + * modules to encrypt/decrypt credential data written/read from this config store file. + * + * @param dataFileName The full path of the data file. + * @throws NullPointerException When data file is empty string. + */ + public WifiConfigStoreEncryptionUtil(@NonNull String dataFileName) { + if (TextUtils.isEmpty(dataFileName)) { + throw new NullPointerException("dataFileName must not be null or the empty " + + "string"); + } + mDataFileName = dataFileName; + } + + private String getKeyAlias() { + return mDataFileName + ALIAS_SUFFIX; + } + + /** + * Encrypt the provided data blob. + * + * @param data Data blob to be encrypted. + * @return Instance of {@link EncryptedData} containing the encrypted info. + */ + public @Nullable EncryptedData encrypt(byte[] data) { + EncryptedData encryptedData = null; + try { + Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); + SecretKey secretKeyReference = getOrCreateSecretKey(getKeyAlias()); + if (secretKeyReference != null) { + cipher.init(Cipher.ENCRYPT_MODE, secretKeyReference); + encryptedData = new EncryptedData(cipher.doFinal(data), cipher.getIV()); + } else { + reportException(new Exception("secretKeyReference is null."), + "secretKeyReference is null."); + } + } catch (NoSuchAlgorithmException e) { + reportException(e, "encrypt could not find the algorithm: " + CIPHER_ALGORITHM); + } catch (NoSuchPaddingException e) { + reportException(e, "encrypt had a padding exception"); + } catch (InvalidKeyException e) { + reportException(e, "encrypt received an invalid key"); + } catch (BadPaddingException e) { + reportException(e, "encrypt had a padding problem"); + } catch (IllegalBlockSizeException e) { + reportException(e, "encrypt had an illegal block size"); + } + return encryptedData; + } + + /** + * Decrypt the original data blob from the provided {@link EncryptedData}. + * + * @param encryptedData Instance of {@link EncryptedData} containing the encrypted info. + * @return Original data blob that was encrypted. + */ + public @Nullable byte[] decrypt(@NonNull EncryptedData encryptedData) { + byte[] decryptedData = null; + try { + Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); + GCMParameterSpec spec = new GCMParameterSpec(GCM_TAG_LENGTH, encryptedData.getIv()); + SecretKey secretKeyReference = getOrCreateSecretKey(getKeyAlias()); + if (secretKeyReference != null) { + cipher.init(Cipher.DECRYPT_MODE, secretKeyReference, spec); + decryptedData = cipher.doFinal(encryptedData.getEncryptedData()); + } + } catch (NoSuchAlgorithmException e) { + reportException(e, "decrypt could not find cipher algorithm " + CIPHER_ALGORITHM); + } catch (NoSuchPaddingException e) { + reportException(e, "decrypt could not find padding algorithm"); + } catch (IllegalBlockSizeException e) { + reportException(e, "decrypt had a illegal block size"); + } catch (BadPaddingException e) { + reportException(e, "decrypt had bad padding"); + } catch (InvalidKeyException e) { + reportException(e, "decrypt had an invalid key"); + } catch (InvalidAlgorithmParameterException e) { + reportException(e, "decrypt had an invalid algorithm parameter"); + } + return decryptedData; + } + + private SecretKey getOrCreateSecretKey(String keyAlias) { + SecretKey secretKey = null; + try { + KeyStore keyStore = AndroidKeyStoreProvider.getKeyStoreForUid(Process.WIFI_UID); + if (keyStore.containsAlias(keyAlias)) { // The key exists in key store. Get the key. + KeyStore.SecretKeyEntry secretKeyEntry = (KeyStore.SecretKeyEntry) keyStore + .getEntry(keyAlias, null); + if (secretKeyEntry != null) { + secretKey = secretKeyEntry.getSecretKey(); + } else { + reportException(new Exception("keystore contains the alias and the secret key " + + "entry was null"), + "keystore contains the alias and the secret key entry was null"); + } + } else { // The key does not exist in key store. Create the key and store it. + KeyGenerator keyGenerator = KeyGenerator + .getInstance(KeyProperties.KEY_ALGORITHM_AES, KEY_STORE); + + KeyGenParameterSpec keyGenParameterSpec = new KeyGenParameterSpec.Builder(keyAlias, + KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT) + .setBlockModes(KeyProperties.BLOCK_MODE_GCM) + .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE) + .setUid(Process.WIFI_UID) + .build(); + + keyGenerator.init(keyGenParameterSpec); + secretKey = keyGenerator.generateKey(); + } + } catch (InvalidAlgorithmParameterException e) { + reportException(e, "getOrCreateSecretKey had an invalid algorithm parameter"); + } catch (KeyStoreException e) { + reportException(e, "getOrCreateSecretKey cannot find the keystore: " + KEY_STORE); + } catch (NoSuchAlgorithmException e) { + reportException(e, "getOrCreateSecretKey cannot find algorithm"); + } catch (NoSuchProviderException e) { + reportException(e, "getOrCreateSecretKey cannot find crypto provider"); + } catch (UnrecoverableEntryException e) { + reportException(e, "getOrCreateSecretKey had an unrecoverable entry exception."); + } + return secretKey; + } + + /* TODO(b/128526030): Remove this error reporting code upon resolving the bug. */ + private static final boolean REQUEST_BUG_REPORT = false; + private void reportException(Exception exception, String error) { + Log.wtf(TAG, "An irrecoverable key store error was encountered: " + error, exception); + if (REQUEST_BUG_REPORT) { + SystemProperties.set("dumpstate.options", "bugreportwifi"); + SystemProperties.set("ctl.start", "bugreport"); + } + } + +} diff --git a/tests/wifitests/src/com/android/server/wifi/DeletedEphemeralSsidsStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/DeletedEphemeralSsidsStoreDataTest.java index 702aa99df..17b9d1c2e 100644 --- a/tests/wifitests/src/com/android/server/wifi/DeletedEphemeralSsidsStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/DeletedEphemeralSsidsStoreDataTest.java @@ -24,6 +24,7 @@ import android.util.Xml; import androidx.test.filters.SmallTest; import com.android.internal.util.FastXmlSerializer; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import org.junit.Before; import org.junit.Test; @@ -78,7 +79,8 @@ public class DeletedEphemeralSsidsStoreDataTest { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mDeletedEphemeralSsidsStoreData.serializeData(out); + mDeletedEphemeralSsidsStoreData.serializeData( + out, mock(WifiConfigStoreEncryptionUtil.class)); out.flush(); return outputStream.toByteArray(); } @@ -94,7 +96,9 @@ public class DeletedEphemeralSsidsStoreDataTest { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); - mDeletedEphemeralSsidsStoreData.deserializeData(in, in.getDepth()); + mDeletedEphemeralSsidsStoreData.deserializeData(in, in.getDepth(), + WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + mock(WifiConfigStoreEncryptionUtil.class)); return mDeletedEphemeralSsidsStoreData.getSsidToTimeMap(); } diff --git a/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java index 7336c4119..20b6c4f76 100644 --- a/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/NetworkListStoreDataTest.java @@ -31,6 +31,7 @@ import android.util.Xml; import androidx.test.filters.SmallTest; import com.android.internal.util.FastXmlSerializer; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtilTest; import org.junit.Before; @@ -213,7 +214,7 @@ public class NetworkListStoreDataTest { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mNetworkListSharedStoreData.serializeData(out); + mNetworkListSharedStoreData.serializeData(out, mock(WifiConfigStoreEncryptionUtil.class)); out.flush(); return outputStream.toByteArray(); } @@ -229,7 +230,9 @@ public class NetworkListStoreDataTest { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); - mNetworkListSharedStoreData.deserializeData(in, in.getDepth()); + mNetworkListSharedStoreData.deserializeData(in, in.getDepth(), + WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + mock(WifiConfigStoreEncryptionUtil.class)); return mNetworkListSharedStoreData.getConfigurations(); } diff --git a/tests/wifitests/src/com/android/server/wifi/NetworkRequestStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/NetworkRequestStoreDataTest.java index f40f71bcf..c0f03505e 100644 --- a/tests/wifitests/src/com/android/server/wifi/NetworkRequestStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/NetworkRequestStoreDataTest.java @@ -27,6 +27,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.util.FastXmlSerializer; import com.android.server.wifi.WifiNetworkFactory.AccessPoint; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import org.junit.Before; import org.junit.Test; @@ -80,7 +81,7 @@ public class NetworkRequestStoreDataTest { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mNetworkRequestStoreData.serializeData(out); + mNetworkRequestStoreData.serializeData(out, mock(WifiConfigStoreEncryptionUtil.class)); out.flush(); return outputStream.toByteArray(); } @@ -92,7 +93,9 @@ public class NetworkRequestStoreDataTest { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); - mNetworkRequestStoreData.deserializeData(in, in.getDepth()); + mNetworkRequestStoreData.deserializeData(in, in.getDepth(), + WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + mock(WifiConfigStoreEncryptionUtil.class)); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionStoreDataTest.java index 5c1dcb459..a35c510fc 100644 --- a/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/NetworkSuggestionStoreDataTest.java @@ -28,6 +28,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.util.FastXmlSerializer; import com.android.server.wifi.WifiNetworkSuggestionsManager.ExtendedWifiNetworkSuggestion; import com.android.server.wifi.WifiNetworkSuggestionsManager.PerAppInfo; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import org.junit.Before; import org.junit.Test; @@ -119,7 +120,7 @@ public class NetworkSuggestionStoreDataTest { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mNetworkSuggestionStoreData.serializeData(out); + mNetworkSuggestionStoreData.serializeData(out, mock(WifiConfigStoreEncryptionUtil.class)); out.flush(); return outputStream.toByteArray(); } @@ -131,7 +132,9 @@ public class NetworkSuggestionStoreDataTest { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); - mNetworkSuggestionStoreData.deserializeData(in, in.getDepth()); + mNetworkSuggestionStoreData.deserializeData(in, in.getDepth(), + WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + mock(WifiConfigStoreEncryptionUtil.class)); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/RandomizedMacStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/RandomizedMacStoreDataTest.java index 4df560fd2..cdd4e6c84 100644 --- a/tests/wifitests/src/com/android/server/wifi/RandomizedMacStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/RandomizedMacStoreDataTest.java @@ -24,6 +24,7 @@ import android.util.Xml; import androidx.test.filters.SmallTest; import com.android.internal.util.FastXmlSerializer; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import org.junit.Before; import org.junit.Test; @@ -62,7 +63,7 @@ public class RandomizedMacStoreDataTest { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mRandomizedMacStoreData.serializeData(out); + mRandomizedMacStoreData.serializeData(out, mock(WifiConfigStoreEncryptionUtil.class)); out.flush(); return outputStream.toByteArray(); } @@ -78,7 +79,9 @@ public class RandomizedMacStoreDataTest { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); - mRandomizedMacStoreData.deserializeData(in, in.getDepth()); + mRandomizedMacStoreData.deserializeData(in, in.getDepth(), + WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + mock(WifiConfigStoreEncryptionUtil.class)); return mRandomizedMacStoreData.getMacMapping(); } diff --git a/tests/wifitests/src/com/android/server/wifi/SsidSetStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/SsidSetStoreDataTest.java index ac6ae21a2..feedc0d2a 100644 --- a/tests/wifitests/src/com/android/server/wifi/SsidSetStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/SsidSetStoreDataTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.any; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -29,6 +30,7 @@ import android.util.Xml; import androidx.test.filters.SmallTest; import com.android.internal.util.FastXmlSerializer; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import org.junit.Before; import org.junit.Test; @@ -80,7 +82,7 @@ public class SsidSetStoreDataTest { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mSsidSetStoreData.serializeData(out); + mSsidSetStoreData.serializeData(out, mock(WifiConfigStoreEncryptionUtil.class)); out.flush(); return outputStream.toByteArray(); } @@ -95,7 +97,9 @@ public class SsidSetStoreDataTest { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); - mSsidSetStoreData.deserializeData(in, in.getDepth()); + mSsidSetStoreData.deserializeData(in, in.getDepth(), + WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + mock(WifiConfigStoreEncryptionUtil.class)); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java index c814aef1a..df93eb4fb 100644 --- a/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WakeupConfigStoreDataTest.java @@ -20,6 +20,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -28,6 +29,7 @@ import android.util.Xml; import androidx.test.filters.SmallTest; import com.android.internal.util.FastXmlSerializer; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.google.android.collect.Sets; @@ -74,7 +76,7 @@ public class WakeupConfigStoreDataTest { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mWakeupConfigData.serializeData(out); + mWakeupConfigData.serializeData(out, mock(WifiConfigStoreEncryptionUtil.class)); out.flush(); return outputStream.toByteArray(); } @@ -88,7 +90,9 @@ public class WakeupConfigStoreDataTest { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); - mWakeupConfigData.deserializeData(in, in.getDepth()); + mWakeupConfigData.deserializeData(in, in.getDepth(), + WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + mock(WifiConfigStoreEncryptionUtil.class)); } /** @@ -177,7 +181,9 @@ public class WakeupConfigStoreDataTest { */ @Test public void hasBeenReadIsTrueWhenUserStoreIsLoaded() throws Exception { - mWakeupConfigData.deserializeData(null /* in */, 0 /* outerTagDepth */); + mWakeupConfigData.deserializeData(null /* in */, 0 /* outerTagDepth */, + WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + mock(WifiConfigStoreEncryptionUtil.class)); assertTrue(mWakeupConfigData.hasBeenRead()); } diff --git a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java index 009429b3f..a004995b9 100644 --- a/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WakeupControllerTest.java @@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -38,6 +39,7 @@ import android.provider.Settings; import androidx.test.filters.SmallTest; import com.android.server.wifi.util.ScanResultUtil; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import org.junit.Before; import org.junit.Test; @@ -149,7 +151,9 @@ public class WakeupControllerTest { private void readUserStore() { try { - mWakeupConfigStoreData.deserializeData(null, 0); + mWakeupConfigStoreData.deserializeData(null, 0, + WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + mock(WifiConfigStoreEncryptionUtil.class)); } catch (XmlPullParserException | IOException e) { // unreachable } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java index b59e367dd..9c16b1257 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigStoreTest.java @@ -21,7 +21,6 @@ import static com.android.server.wifi.WifiConfigStore.ZEROED_ENCRYPTED_DATA; import static org.junit.Assert.*; import static org.mockito.Mockito.*; -import android.app.test.MockAnswerUtil.AnswerWithArguments; import android.app.test.TestAlarmManager; import android.content.Context; import android.content.pm.PackageManager; @@ -34,8 +33,8 @@ import androidx.test.filters.SmallTest; import com.android.internal.util.ArrayUtils; import com.android.server.wifi.WifiConfigStore.StoreData; import com.android.server.wifi.WifiConfigStore.StoreFile; -import com.android.server.wifi.util.DataIntegrityChecker; import com.android.server.wifi.util.EncryptedData; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; import libcore.util.HexEncoding; @@ -43,7 +42,6 @@ import libcore.util.HexEncoding; import org.junit.After; 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; @@ -73,13 +71,7 @@ public class WifiConfigStoreTest { private static final String TEST_DATA_XML_STRING_FORMAT = "\n" + "\n" - + "\n" - + "\n" - + "000000000000000000000000000000" - + "000000000000000000000000000000000000000000000000000000000000000000" - + "\n" - + "000000000000000000000000\n" - + "\n" + + "\n" + "\n" + "\n" + "\n" @@ -172,7 +164,7 @@ public class WifiConfigStoreTest { private TestLooper mLooper; @Mock private Clock mClock; @Mock private WifiMetrics mWifiMetrics; - @Mock private DataIntegrityChecker mDataIntegrityChecker; + @Mock private WifiConfigStoreEncryptionUtil mEncryptionUtil; private MockStoreFile mSharedStore; private MockStoreFile mUserStore; private MockStoreFile mUserNetworkSuggestionsStore; @@ -196,10 +188,10 @@ public class WifiConfigStoreTest { .thenReturn(mAlarmManager.getAlarmManager()); when(mContext.getPackageManager()).thenReturn(mPackageManager); when(mPackageManager.getNameForUid(anyInt())).thenReturn(TEST_CREATOR_NAME); - when(mDataIntegrityChecker.compute(any(byte[].class))) + when(mEncryptionUtil.encrypt(any(byte[].class))) .thenReturn(ZEROED_ENCRYPTED_DATA); - when(mDataIntegrityChecker.isOk(any(byte[].class), any(EncryptedData.class))) - .thenReturn(true); + when(mEncryptionUtil.decrypt(any(EncryptedData.class))) + .thenReturn(new byte[0]); mSharedStore = new MockStoreFile(WifiConfigStore.STORE_FILE_SHARED_GENERAL); mUserStore = new MockStoreFile(WifiConfigStore.STORE_FILE_USER_GENERAL); mUserNetworkSuggestionsStore = @@ -432,9 +424,9 @@ public class WifiConfigStoreTest { // Ensure that we got the call to deserialize empty shared data, but no user data. verify(sharedStoreData).resetData(); - verify(sharedStoreData).deserializeData(eq(null), anyInt()); + verify(sharedStoreData).deserializeData(eq(null), anyInt(), anyInt(), any()); verify(userStoreData, never()).resetData(); - verify(userStoreData, never()).deserializeData(any(), anyInt()); + verify(userStoreData, never()).deserializeData(any(), anyInt(), anyInt(), any()); } /** @@ -462,9 +454,9 @@ public class WifiConfigStoreTest { // Ensure that we got the call to deserialize empty shared & user data. verify(userStoreData).resetData(); - verify(userStoreData).deserializeData(eq(null), anyInt()); + verify(userStoreData).deserializeData(eq(null), anyInt(), anyInt(), any()); verify(sharedStoreData).resetData(); - verify(sharedStoreData).deserializeData(eq(null), anyInt()); + verify(sharedStoreData).deserializeData(eq(null), anyInt(), anyInt(), any()); } /** @@ -639,9 +631,9 @@ public class WifiConfigStoreTest { mUserStore.storeRawDataToWrite(null); mWifiConfigStore.read(); - verify(storeData1).deserializeData(notNull(), anyInt()); - verify(storeData1, never()).deserializeData(eq(null), anyInt()); - verify(storeData2).deserializeData(eq(null), anyInt()); + verify(storeData1).deserializeData(notNull(), anyInt(), anyInt(), any()); + verify(storeData1, never()).deserializeData(eq(null), anyInt(), anyInt(), any()); + verify(storeData2).deserializeData(eq(null), anyInt(), anyInt(), any()); reset(storeData1, storeData2); // Scenario 2: StoreData2 in user store file. @@ -655,9 +647,9 @@ public class WifiConfigStoreTest { mUserStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData2.getBytes()); mWifiConfigStore.read(); - verify(storeData1).deserializeData(eq(null), anyInt()); - verify(storeData2).deserializeData(notNull(), anyInt()); - verify(storeData2, never()).deserializeData(eq(null), anyInt()); + verify(storeData1).deserializeData(eq(null), anyInt(), anyInt(), any()); + verify(storeData2).deserializeData(notNull(), anyInt(), anyInt(), any()); + verify(storeData2, never()).deserializeData(eq(null), anyInt(), anyInt(), any()); reset(storeData1, storeData2); // Scenario 3: StoreData1 in shared store file & StoreData2 in user store file. @@ -671,10 +663,10 @@ public class WifiConfigStoreTest { mUserStore.storeRawDataToWrite(fileContentsXmlStringWithOnlyStoreData2.getBytes()); mWifiConfigStore.read(); - verify(storeData1).deserializeData(notNull(), anyInt()); - verify(storeData1, never()).deserializeData(eq(null), anyInt()); - verify(storeData2).deserializeData(notNull(), anyInt()); - verify(storeData2, never()).deserializeData(eq(null), anyInt()); + verify(storeData1).deserializeData(notNull(), anyInt(), anyInt(), any()); + verify(storeData1, never()).deserializeData(eq(null), anyInt(), anyInt(), any()); + verify(storeData2).deserializeData(notNull(), anyInt(), anyInt(), any()); + verify(storeData2, never()).deserializeData(eq(null), anyInt(), anyInt(), any()); reset(storeData1, storeData2); // Scenario 4: StoreData1 & StoreData2 in shared store file. @@ -689,10 +681,10 @@ public class WifiConfigStoreTest { mUserStore.storeRawDataToWrite(null); mWifiConfigStore.read(); - verify(storeData1).deserializeData(notNull(), anyInt()); - verify(storeData1, never()).deserializeData(eq(null), anyInt()); - verify(storeData2).deserializeData(notNull(), anyInt()); - verify(storeData2, never()).deserializeData(eq(null), anyInt()); + verify(storeData1).deserializeData(notNull(), anyInt(), anyInt(), any()); + verify(storeData1, never()).deserializeData(eq(null), anyInt(), anyInt(), any()); + verify(storeData2).deserializeData(notNull(), anyInt(), anyInt(), any()); + verify(storeData2, never()).deserializeData(eq(null), anyInt(), anyInt(), any()); reset(storeData1, storeData2); } @@ -739,9 +731,9 @@ public class WifiConfigStoreTest { verify(userStoreNetworkSuggestionsData).hasNewDataToSerialize(); // Verify that we serialized data from the first 2 data source, but not from the last one. - verify(sharedStoreData).serializeData(any()); - verify(userStoreData).serializeData(any()); - verify(userStoreNetworkSuggestionsData, never()).serializeData(any()); + verify(sharedStoreData).serializeData(any(), any()); + verify(userStoreData).serializeData(any(), any()); + verify(userStoreNetworkSuggestionsData, never()).serializeData(any(), any()); } /** @@ -815,188 +807,19 @@ public class WifiConfigStoreTest { // Read and verify the data content in the store file (metadata stripped out) has been sent // to the corresponding store data when integrity check passes. mWifiConfigStore.read(); - verify(sharedStoreData, times(1)).deserializeData(any(XmlPullParser.class), anyInt()); - verify(userStoreData, times(1)).deserializeData(any(XmlPullParser.class), anyInt()); - - // We shouldn't perform any data integrity checks on version 1 file. - verifyZeroInteractions(mDataIntegrityChecker); - } - - /** - * Tests the read API behaviour when integrity check fails. - * Expected behaviour: The read should return an empty store data. - */ - @Test - public void testReadWhenIntegrityCheckFails() throws Exception { - // Register data container. - StoreData sharedStoreData = mock(StoreData.class); - when(sharedStoreData.getStoreFileId()) - .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); - when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA); - StoreData userStoreData = mock(StoreData.class); - when(userStoreData.getStoreFileId()) - .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); - when(userStoreData.getName()).thenReturn(TEST_USER_DATA); - mWifiConfigStore.registerStoreData(sharedStoreData); - mWifiConfigStore.registerStoreData(userStoreData); - - // Read both share and user config store. - mWifiConfigStore.setUserStores(mUserStores); - - // Now store some content in the shared and user data files. - mUserStore.storeRawDataToWrite( - String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE, - HexEncoding.encodeToString(ZEROED_ENCRYPTED_DATA.getEncryptedData()), - HexEncoding.encodeToString(ZEROED_ENCRYPTED_DATA.getIv()), - TEST_USER_DATA).getBytes()); - mSharedStore.storeRawDataToWrite( - String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE, - HexEncoding.encodeToString(ZEROED_ENCRYPTED_DATA.getEncryptedData()), - HexEncoding.encodeToString(ZEROED_ENCRYPTED_DATA.getIv()), - TEST_SHARE_DATA).getBytes()); - - // Read and verify the data content in the store file (metadata stripped out) has been sent - // to the corresponding store data when integrity check passes. - mWifiConfigStore.read(); - verify(sharedStoreData, times(1)).deserializeData(any(XmlPullParser.class), anyInt()); - verify(userStoreData, times(1)).deserializeData(any(XmlPullParser.class), anyInt()); - - // Read and verify the data content in the store file (metadata stripped out) has not been - // sent to the corresponding store data when integrity check fails. - when(mDataIntegrityChecker.isOk(any(byte[].class), any(EncryptedData.class))) - .thenReturn(false); - mWifiConfigStore.read(); - verify(sharedStoreData, times(1)).deserializeData(any(XmlPullParser.class), anyInt()); - verify(userStoreData, times(1)).deserializeData(any(XmlPullParser.class), anyInt()); - } - - /** - * Tests the write API behaviour when integrity check fails. - * Expected behaviour: The read should return an empty store data. - */ - @Test - public void testWriteWhenIntegrityComputeFails() throws Exception { - // Register data container. - StoreData sharedStoreData = mock(StoreData.class); - when(sharedStoreData.getStoreFileId()) - .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); - when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA); - when(sharedStoreData.hasNewDataToSerialize()).thenReturn(true); - StoreData userStoreData = mock(StoreData.class); - when(userStoreData.getStoreFileId()) - .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); - when(userStoreData.getName()).thenReturn(TEST_USER_DATA); - when(userStoreData.hasNewDataToSerialize()).thenReturn(true); - mWifiConfigStore.registerStoreData(sharedStoreData); - mWifiConfigStore.registerStoreData(userStoreData); - - // Read both share and user config store. - mWifiConfigStore.setUserStores(mUserStores); - - // Reset store file contents & ensure that the user and store data files are empty. - mUserStore.storeRawDataToWrite(null); - mSharedStore.storeRawDataToWrite(null); - assertNull(mUserStore.getStoreBytes()); - assertNull(mSharedStore.getStoreBytes()); - - // Write and verify that the data is written to the config store file when integrity - // computation passes. - mWifiConfigStore.write(true); - assertNotNull(mUserStore.getStoreBytes()); - assertNotNull(mSharedStore.getStoreBytes()); - assertTrue(new String(mUserStore.getStoreBytes()).contains(TEST_USER_DATA)); - assertTrue(new String(mSharedStore.getStoreBytes()).contains(TEST_SHARE_DATA)); - - // Reset store file contents & ensure that the user and store data files are empty. - mUserStore.storeRawDataToWrite(null); - mSharedStore.storeRawDataToWrite(null); - assertNull(mUserStore.getStoreBytes()); - assertNull(mSharedStore.getStoreBytes()); - - // Write and verify that the data is not written to the config store file when integrity - // computation fails. - when(mDataIntegrityChecker.compute(any(byte[].class))).thenReturn(null); - mWifiConfigStore.write(true); - assertNull(mUserStore.getStoreBytes()); - assertNull(mSharedStore.getStoreBytes()); - } - - /** - * Tests the write API behaviour to ensure that the integrity data is written to the file. - */ - @Test - public void testWriteContainsIntegrityData() throws Exception { - byte[] encryptedData = new byte[EncryptedData.ENCRYPTED_DATA_LENGTH]; - byte[] iv = new byte[EncryptedData.IV_LENGTH]; - Random random = new Random(); - random.nextBytes(encryptedData); - random.nextBytes(iv); - final EncryptedData testEncryptedData = new EncryptedData(encryptedData, iv); - - doAnswer(new AnswerWithArguments() { - public EncryptedData answer(byte[] data) { - String storeXmlString = new String(data); - // Verify that we fill in zeros to the data when we compute integrity. - if (storeXmlString.contains(TEST_SHARE_DATA)) { - assertEquals(String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE, - HexEncoding.encodeToString(ZEROED_ENCRYPTED_DATA.getEncryptedData()), - HexEncoding.encodeToString(ZEROED_ENCRYPTED_DATA.getIv()), - TEST_SHARE_DATA), storeXmlString); - } else if (storeXmlString.contains(TEST_USER_DATA)) { - assertEquals(String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE, - HexEncoding.encodeToString(ZEROED_ENCRYPTED_DATA.getEncryptedData()), - HexEncoding.encodeToString(ZEROED_ENCRYPTED_DATA.getIv()), - TEST_USER_DATA), storeXmlString); - } - return testEncryptedData; - } - }).when(mDataIntegrityChecker).compute(any(byte[].class)); - - // Register data container. - StoreData sharedStoreData = mock(StoreData.class); - when(sharedStoreData.getStoreFileId()) - .thenReturn(WifiConfigStore.STORE_FILE_SHARED_GENERAL); - when(sharedStoreData.getName()).thenReturn(TEST_SHARE_DATA); - when(sharedStoreData.hasNewDataToSerialize()).thenReturn(true); - StoreData userStoreData = mock(StoreData.class); - when(userStoreData.getStoreFileId()) - .thenReturn(WifiConfigStore.STORE_FILE_USER_GENERAL); - when(userStoreData.getName()).thenReturn(TEST_USER_DATA); - when(userStoreData.hasNewDataToSerialize()).thenReturn(true); - mWifiConfigStore.registerStoreData(sharedStoreData); - mWifiConfigStore.registerStoreData(userStoreData); - - // Read both share and user config store. - mWifiConfigStore.setUserStores(mUserStores); - - // Write and verify that the data is written to the config store file when integrity - // computation passes. - mWifiConfigStore.write(true); - - // Verify that we fill in zeros to the data when we computed integrity. - verify(mDataIntegrityChecker, times(2)).compute(any(byte[].class)); - - // Verify the parsed integrity data - assertNotNull(mUserStore.getStoreBytes()); - assertNotNull(mSharedStore.getStoreBytes()); - String userStoreXmlString = new String(mUserStore.getStoreBytes()); - String sharedStoreXmlString = new String(mSharedStore.getStoreBytes()); - assertEquals(String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE, - HexEncoding.encodeToString(encryptedData).toLowerCase(), - HexEncoding.encodeToString(iv).toLowerCase(), - TEST_USER_DATA), userStoreXmlString); - assertEquals(String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE, - HexEncoding.encodeToString(encryptedData).toLowerCase(), - HexEncoding.encodeToString(iv).toLowerCase(), - TEST_SHARE_DATA), sharedStoreXmlString); + verify(sharedStoreData, times(1)).deserializeData( + any(XmlPullParser.class), anyInt(), + eq(WifiConfigStore.INITIAL_CONFIG_STORE_DATA_VERSION), any()); + verify(userStoreData, times(1)).deserializeData( + any(XmlPullParser.class), anyInt(), + eq(WifiConfigStore.INITIAL_CONFIG_STORE_DATA_VERSION), any()); } /** - * Tests the read API behaviour to ensure that the integrity data is parsed from the file and - * used for checking integrity of the file. + * Tests the read API behaviour to ensure that the integrity data is parsed from the file. */ @Test - public void testReadParsesIntegrityData() throws Exception { + public void testReadVersion2StoreFile() throws Exception { byte[] encryptedData = new byte[EncryptedData.ENCRYPTED_DATA_LENGTH]; byte[] iv = new byte[EncryptedData.IV_LENGTH]; Random random = new Random(); @@ -1033,40 +856,14 @@ public class WifiConfigStoreTest { TEST_SHARE_DATA).getBytes()); // Read and verify the data content in the store file (metadata stripped out) has been sent - // to the corresponding store data when integrity check passes. + // to the corresponding store data. mWifiConfigStore.read(); - verify(sharedStoreData, times(1)).deserializeData(any(XmlPullParser.class), anyInt()); - verify(userStoreData, times(1)).deserializeData(any(XmlPullParser.class), anyInt()); - - // Verify that we parsed the integrity data and used it for checking integrity of the file. - ArgumentCaptor integrityCaptor = - ArgumentCaptor.forClass(EncryptedData.class); - ArgumentCaptor dataCaptor = ArgumentCaptor.forClass(byte[].class); - // Will be invoked twice for each file - shared & user store file. - verify(mDataIntegrityChecker, times(2)).isOk( - dataCaptor.capture(), integrityCaptor.capture()); - // Verify the parsed integrity data - assertEquals(2, integrityCaptor.getAllValues().size()); - EncryptedData parsedEncryptedData1 = integrityCaptor.getAllValues().get(0); - assertArrayEquals(encryptedData, parsedEncryptedData1.getEncryptedData()); - assertArrayEquals(iv, parsedEncryptedData1.getIv()); - EncryptedData parsedEncryptedData2 = integrityCaptor.getAllValues().get(1); - assertArrayEquals(encryptedData, parsedEncryptedData2.getEncryptedData()); - assertArrayEquals(iv, parsedEncryptedData2.getIv()); - - // Verify that we fill in zeros to the data when we performed integrity checked. - assertEquals(2, dataCaptor.getAllValues().size()); - String sharedStoreXmlStringWithZeroedIntegrity = - new String(dataCaptor.getAllValues().get(0)); - assertEquals(String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE, - HexEncoding.encodeToString(ZEROED_ENCRYPTED_DATA.getEncryptedData()), - HexEncoding.encodeToString(ZEROED_ENCRYPTED_DATA.getIv()), - TEST_SHARE_DATA), sharedStoreXmlStringWithZeroedIntegrity); - String userStoreXmlStringWithZeroedIntegrity = new String(dataCaptor.getAllValues().get(1)); - assertEquals(String.format(TEST_DATA_XML_STRING_FORMAT_V2_WITH_ONE_DATA_SOURCE, - HexEncoding.encodeToString(ZEROED_ENCRYPTED_DATA.getEncryptedData()), - HexEncoding.encodeToString(ZEROED_ENCRYPTED_DATA.getIv()), - TEST_USER_DATA), userStoreXmlStringWithZeroedIntegrity); + verify(sharedStoreData, times(1)) + .deserializeData(any(XmlPullParser.class), anyInt(), + eq(WifiConfigStore.INTEGRITY_CONFIG_STORE_DATA_VERSION), any()); + verify(userStoreData, times(1)) + .deserializeData(any(XmlPullParser.class), anyInt(), + eq(WifiConfigStore.INTEGRITY_CONFIG_STORE_DATA_VERSION), any()); } /** @@ -1078,7 +875,7 @@ public class WifiConfigStoreTest { private boolean mStoreWritten; MockStoreFile(@WifiConfigStore.StoreFileId int fileId) { - super(new File("MockStoreFile"), fileId, mDataIntegrityChecker); + super(new File("MockStoreFile"), fileId, mEncryptionUtil); } @Override @@ -1129,13 +926,14 @@ public class WifiConfigStoreTest { } @Override - public void serializeData(XmlSerializer out) + public void serializeData(XmlSerializer out, WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { XmlUtil.writeNextValue(out, XML_TAG_TEST_DATA, mData); } @Override - public void deserializeData(XmlPullParser in, int outerTagDepth) + public void deserializeData(XmlPullParser in, int outerTagDepth, int version, + WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { if (in == null) { return; diff --git a/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java b/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java index 222c4953a..d20c99c4f 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiNetworkFactoryTest.java @@ -68,6 +68,7 @@ import com.android.internal.util.FastXmlSerializer; import com.android.server.wifi.WifiNetworkFactory.AccessPoint; import com.android.server.wifi.nano.WifiMetricsProto; import com.android.server.wifi.util.ScanResultUtil; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.WifiPermissionsUtil; import org.junit.After; @@ -2932,7 +2933,7 @@ public class WifiNetworkFactoryTest { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mNetworkRequestStoreData.serializeData(out); + mNetworkRequestStoreData.serializeData(out, mock(WifiConfigStoreEncryptionUtil.class)); out.flush(); return outputStream.toByteArray(); } @@ -2947,6 +2948,8 @@ public class WifiNetworkFactoryTest { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); - mNetworkRequestStoreData.deserializeData(in, in.getDepth()); + mNetworkRequestStoreData.deserializeData(in, in.getDepth(), + WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + mock(WifiConfigStoreEncryptionUtil.class)); } } diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreDataTest.java index c76e2c878..7a815001c 100644 --- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreDataTest.java @@ -25,6 +25,7 @@ import androidx.test.filters.SmallTest; import com.android.internal.util.FastXmlSerializer; import com.android.server.wifi.WifiConfigStore; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import org.junit.Before; import org.junit.Test; @@ -62,7 +63,7 @@ public class PasspointConfigSharedStoreDataTest { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mConfigStoreData.serializeData(out); + mConfigStoreData.serializeData(out, mock(WifiConfigStoreEncryptionUtil.class)); out.flush(); return outputStream.toByteArray(); } @@ -77,7 +78,9 @@ public class PasspointConfigSharedStoreDataTest { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); - mConfigStoreData.deserializeData(in, in.getDepth()); + mConfigStoreData.deserializeData(in, in.getDepth(), + WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + mock(WifiConfigStoreEncryptionUtil.class)); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigUserStoreDataTest.java b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigUserStoreDataTest.java index 82cdb5a90..5278e1933 100644 --- a/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigUserStoreDataTest.java +++ b/tests/wifitests/src/com/android/server/wifi/hotspot2/PasspointConfigUserStoreDataTest.java @@ -32,6 +32,7 @@ import com.android.internal.util.FastXmlSerializer; import com.android.server.wifi.SIMAccessor; import com.android.server.wifi.WifiConfigStore; import com.android.server.wifi.WifiKeyStore; +import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import org.junit.Before; import org.junit.Test; @@ -213,7 +214,7 @@ public class PasspointConfigUserStoreDataTest { final XmlSerializer out = new FastXmlSerializer(); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); - mConfigStoreData.serializeData(out); + mConfigStoreData.serializeData(out, mock(WifiConfigStoreEncryptionUtil.class)); out.flush(); return outputStream.toByteArray(); } @@ -228,7 +229,9 @@ public class PasspointConfigUserStoreDataTest { final XmlPullParser in = Xml.newPullParser(); final ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); - mConfigStoreData.deserializeData(in, in.getDepth()); + mConfigStoreData.deserializeData(in, in.getDepth(), + WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + mock(WifiConfigStoreEncryptionUtil.class)); } /** diff --git a/tests/wifitests/src/com/android/server/wifi/util/DataIntegrityCheckerTest.java b/tests/wifitests/src/com/android/server/wifi/util/DataIntegrityCheckerTest.java deleted file mode 100644 index c281b6440..000000000 --- a/tests/wifitests/src/com/android/server/wifi/util/DataIntegrityCheckerTest.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.server.wifi.util; - -import static org.junit.Assert.*; - -import org.junit.Ignore; -import org.junit.Test; - -import java.io.File; - -/** - * Unit tests for {@link com.android.server.wifi.util.DataIntegrityChecker}. - */ -public class DataIntegrityCheckerTest { - private static byte[] sGoodData = {1, 2, 3, 4}; - private static byte[] sBadData = {5, 6, 7, 8}; - - /** - * Verify that updating the integrity token with known data and alias will - * pass the integrity test. This test ensure the expected outcome for - * unedited data succeeds. - * - * @throws Exception - */ - @Test - @Ignore - public void testIntegrityWithKnownDataAndKnownAlias() throws Exception { - File integrityFile = File.createTempFile("testIntegrityWithKnownDataAndKnownAlias", - ".tmp"); - DataIntegrityChecker dataIntegrityChecker = new DataIntegrityChecker( - integrityFile.getParent()); - EncryptedData encryptedData = dataIntegrityChecker.compute(sGoodData); - assertTrue(dataIntegrityChecker.isOk(sGoodData, encryptedData)); - } - - /** - * Verify that checking the integrity of unknown data and a known alias - * will fail the integrity test. This test ensure the expected failure for - * altered data, in fact, fails. - * - * - * @throws Exception - */ - @Test - @Ignore - public void testIntegrityWithUnknownDataAndKnownAlias() throws Exception { - File integrityFile = File.createTempFile("testIntegrityWithUnknownDataAndKnownAlias", - ".tmp"); - DataIntegrityChecker dataIntegrityChecker = new DataIntegrityChecker( - integrityFile.getParent()); - EncryptedData encryptedData = dataIntegrityChecker.compute(sGoodData); - assertFalse(dataIntegrityChecker.isOk(sBadData, encryptedData)); - } -} -- cgit v1.2.3 From 6237115f3c6ae723eb3927640c843714793fbe59 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Tue, 22 Oct 2019 15:37:41 -0700 Subject: WifiConfigStore: Encrypt credentials for networks (2/4) Plumb the EncryptionUtil & version info to the XmlUtil classes that actually handle the serialization/deserialization of data. Also, created a helper class to serialize/deserialize EncryptedData class. Bug: 140485110 Test: atest com.android.server.wifi Change-Id: I92846f1fb63f3b85892750b195a535bcfdc03e2c Merged-In: I92846f1fb63f3b85892750b195a535bcfdc03e2c --- .../android/server/wifi/NetworkListStoreData.java | 48 +++++++--- .../server/wifi/NetworkSuggestionStoreData.java | 49 ++++++---- .../com/android/server/wifi/WifiConfigStore.java | 5 +- .../java/com/android/server/wifi/util/XmlUtil.java | 100 ++++++++++++++++++--- .../com/android/server/wifi/util/XmlUtilTest.java | 12 ++- 5 files changed, 164 insertions(+), 50 deletions(-) diff --git a/service/java/com/android/server/wifi/NetworkListStoreData.java b/service/java/com/android/server/wifi/NetworkListStoreData.java index 981e97c7e..4f2f36b9b 100644 --- a/service/java/com/android/server/wifi/NetworkListStoreData.java +++ b/service/java/com/android/server/wifi/NetworkListStoreData.java @@ -16,6 +16,8 @@ package com.android.server.wifi; +import static com.android.server.wifi.WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION; + import android.annotation.NonNull; import android.content.Context; import android.net.IpConfiguration; @@ -71,7 +73,7 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData public void serializeData(XmlSerializer out, @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { - serializeNetworkList(out, mConfigurations); + serializeNetworkList(out, mConfigurations, encryptionUtil); } @Override @@ -83,7 +85,7 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData if (in == null) { return; } - mConfigurations = parseNetworkList(in, outerTagDepth); + mConfigurations = parseNetworkList(in, outerTagDepth, version, encryptionUtil); } @Override @@ -123,33 +125,38 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData * * @param out The output stream to serialize the data to * @param networkList The network list to serialize + * @param encryptionUtil Instance of {@link WifiConfigStoreEncryptionUtil} * @throws XmlPullParserException * @throws IOException */ - private void serializeNetworkList(XmlSerializer out, List networkList) + private void serializeNetworkList(XmlSerializer out, List networkList, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { if (networkList == null) { return; } for (WifiConfiguration network : networkList) { - serializeNetwork(out, network); + serializeNetwork(out, network, encryptionUtil); } } /** * Serialize a {@link WifiConfiguration} to an output stream in XML format. - * @param out - * @param config + * + * @param out The output stream to serialize the data to + * @param config The network config to serialize + * @param encryptionUtil Instance of {@link WifiConfigStoreEncryptionUtil} * @throws XmlPullParserException * @throws IOException */ - private void serializeNetwork(XmlSerializer out, WifiConfiguration config) + private void serializeNetwork(XmlSerializer out, WifiConfiguration config, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK); // Serialize WifiConfiguration. XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); - WifiConfigurationXmlUtil.writeToXmlForConfigStore(out, config); + WifiConfigurationXmlUtil.writeToXmlForConfigStore(out, config, encryptionUtil); XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); // Serialize network selection status. @@ -167,7 +174,7 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData && config.enterpriseConfig.getEapMethod() != WifiEnterpriseConfig.Eap.NONE) { XmlUtil.writeNextSectionStart( out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION); - WifiEnterpriseConfigXmlUtil.writeToXml(out, config.enterpriseConfig); + WifiEnterpriseConfigXmlUtil.writeToXml(out, config.enterpriseConfig, encryptionUtil); XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION); } @@ -179,11 +186,15 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData * * @param in The input stream to read from * @param outerTagDepth The XML tag depth of the outer XML block + * @param version Version of config store file. + * @param encryptionUtil Instance of {@link WifiConfigStoreEncryptionUtil} * @return List of {@link WifiConfiguration} * @throws XmlPullParserException * @throws IOException */ - private List parseNetworkList(XmlPullParser in, int outerTagDepth) + private List parseNetworkList(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { List networkList = new ArrayList<>(); while (XmlUtil.gotoNextSectionWithNameOrEnd(in, XML_TAG_SECTION_HEADER_NETWORK, @@ -191,7 +202,8 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData // Try/catch only runtime exceptions (like illegal args), any XML/IO exceptions are // fatal and should abort the entire loading process. try { - WifiConfiguration config = parseNetwork(in, outerTagDepth + 1); + WifiConfiguration config = + parseNetwork(in, outerTagDepth + 1, version, encryptionUtil); networkList.add(config); } catch (RuntimeException e) { // Failed to parse this network, skip it. @@ -206,11 +218,15 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData * * @param in The input stream to read from * @param outerTagDepth The XML tag depth of the outer XML block + * @param version Version of config store file. + * @param encryptionUtil Instance of {@link WifiConfigStoreEncryptionUtil} * @return {@link WifiConfiguration} * @throws XmlPullParserException * @throws IOException */ - private WifiConfiguration parseNetwork(XmlPullParser in, int outerTagDepth) + private WifiConfiguration parseNetwork(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { Pair parsedConfig = null; NetworkSelectionStatus status = null; @@ -225,7 +241,9 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData throw new XmlPullParserException("Detected duplicate tag for: " + XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); } - parsedConfig = WifiConfigurationXmlUtil.parseFromXml(in, outerTagDepth + 1); + parsedConfig = WifiConfigurationXmlUtil.parseFromXml(in, outerTagDepth + 1, + version >= ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + encryptionUtil); break; case XML_TAG_SECTION_HEADER_NETWORK_STATUS: if (status != null) { @@ -247,7 +265,9 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData + XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION); } enterpriseConfig = - WifiEnterpriseConfigXmlUtil.parseFromXml(in, outerTagDepth + 1); + WifiEnterpriseConfigXmlUtil.parseFromXml(in, outerTagDepth + 1, + version >= ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + encryptionUtil); break; default: throw new XmlPullParserException("Unknown tag under " diff --git a/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java b/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java index e9503b7e4..fc0c55b5a 100644 --- a/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java +++ b/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java @@ -16,6 +16,8 @@ package com.android.server.wifi; +import static com.android.server.wifi.WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION; + import android.annotation.NonNull; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; @@ -103,7 +105,7 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { public void serializeData(XmlSerializer out, @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { - serializeNetworkSuggestionsMap(out, mDataSource.toSerialize()); + serializeNetworkSuggestionsMap(out, mDataSource.toSerialize(), encryptionUtil); } @Override @@ -115,7 +117,8 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { if (in == null) { return; } - mDataSource.fromDeserialized(parseNetworkSuggestionsMap(in, outerTagDepth)); + mDataSource.fromDeserialized( + parseNetworkSuggestionsMap(in, outerTagDepth, version, encryptionUtil)); } @Override @@ -145,7 +148,8 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { * @throws IOException */ private void serializeNetworkSuggestionsMap( - XmlSerializer out, final Map networkSuggestionsMap) + XmlSerializer out, final Map networkSuggestionsMap, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { if (networkSuggestionsMap == null) { return; @@ -160,7 +164,7 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { XmlUtil.writeNextValue(out, XML_TAG_SUGGESTOR_PACKAGE_NAME, packageName); XmlUtil.writeNextValue(out, XML_TAG_SUGGESTOR_HAS_USER_APPROVED, hasUserApproved); XmlUtil.writeNextValue(out, XML_TAG_SUGGESTOR_MAX_SIZE, maxSize); - serializeExtNetworkSuggestions(out, networkSuggestions); + serializeExtNetworkSuggestions(out, networkSuggestions, encryptionUtil); XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION_PER_APP); } } @@ -172,10 +176,11 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { * @throws IOException */ private void serializeExtNetworkSuggestions( - XmlSerializer out, final Set extNetworkSuggestions) + XmlSerializer out, final Set extNetworkSuggestions, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { for (ExtendedWifiNetworkSuggestion extNetworkSuggestion : extNetworkSuggestions) { - serializeNetworkSuggestion(out, extNetworkSuggestion.wns); + serializeNetworkSuggestion(out, extNetworkSuggestion.wns, encryptionUtil); } } @@ -186,13 +191,15 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { * @throws IOException */ private void serializeNetworkSuggestion(XmlSerializer out, - final WifiNetworkSuggestion suggestion) + final WifiNetworkSuggestion suggestion, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION); // Serialize WifiConfiguration. XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); - WifiConfigurationXmlUtil.writeToXmlForConfigStore(out, suggestion.wifiConfiguration); + WifiConfigurationXmlUtil.writeToXmlForConfigStore( + out, suggestion.wifiConfiguration, encryptionUtil); XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); // Serialize enterprise configuration for enterprise networks. if (suggestion.wifiConfiguration.enterpriseConfig != null @@ -201,7 +208,7 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { XmlUtil.writeNextSectionStart( out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION); XmlUtil.WifiEnterpriseConfigXmlUtil.writeToXml( - out, suggestion.wifiConfiguration.enterpriseConfig); + out, suggestion.wifiConfiguration.enterpriseConfig, encryptionUtil); XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION); } @@ -223,7 +230,9 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { * @throws XmlPullParserException * @throws IOException */ - private Map parseNetworkSuggestionsMap(XmlPullParser in, int outerTagDepth) + private Map parseNetworkSuggestionsMap(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { Map networkSuggestionsMap = new HashMap<>(); while (XmlUtil.gotoNextSectionWithNameOrEnd( @@ -238,7 +247,8 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { int maxSize = (int) XmlUtil.readNextValueWithName(in, XML_TAG_SUGGESTOR_MAX_SIZE); PerAppInfo perAppInfo = new PerAppInfo(packageName); Set extNetworkSuggestions = - parseExtNetworkSuggestions(in, outerTagDepth + 1, perAppInfo); + parseExtNetworkSuggestions( + in, outerTagDepth + 1, version, encryptionUtil, perAppInfo); perAppInfo.hasUserApproved = hasUserApproved; perAppInfo.maxSize = maxSize; perAppInfo.extNetworkSuggestions.addAll(extNetworkSuggestions); @@ -258,7 +268,8 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { * @throws IOException */ private Set parseExtNetworkSuggestions( - XmlPullParser in, int outerTagDepth, PerAppInfo perAppInfo) + XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil, PerAppInfo perAppInfo) throws XmlPullParserException, IOException { Set extNetworkSuggestions = new HashSet<>(); while (XmlUtil.gotoNextSectionWithNameOrEnd( @@ -267,7 +278,7 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { // fatal and should abort the entire loading process. try { WifiNetworkSuggestion networkSuggestion = - parseNetworkSuggestion(in, outerTagDepth + 1); + parseNetworkSuggestion(in, outerTagDepth + 1, version, encryptionUtil); extNetworkSuggestions.add(ExtendedWifiNetworkSuggestion.fromWns( networkSuggestion, perAppInfo)); } catch (RuntimeException e) { @@ -284,7 +295,9 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { * @throws XmlPullParserException * @throws IOException */ - private WifiNetworkSuggestion parseNetworkSuggestion(XmlPullParser in, int outerTagDepth) + private WifiNetworkSuggestion parseNetworkSuggestion(XmlPullParser in, int outerTagDepth, + @WifiConfigStore.Version int version, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { Pair parsedConfig = null; WifiEnterpriseConfig enterpriseConfig = null; @@ -329,7 +342,9 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { + XML_TAG_SECTION_HEADER_WIFI_CONFIGURATION); } parsedConfig = WifiConfigurationXmlUtil.parseFromXml( - in, outerTagDepth + 1); + in, outerTagDepth + 1, + version >= ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + encryptionUtil); break; case XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION: if (enterpriseConfig != null) { @@ -337,7 +352,9 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { + XML_TAG_SECTION_HEADER_WIFI_ENTERPRISE_CONFIGURATION); } enterpriseConfig = XmlUtil.WifiEnterpriseConfigXmlUtil.parseFromXml( - in, outerTagDepth + 1); + in, outerTagDepth + 1, + version >= ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION, + encryptionUtil); break; default: throw new XmlPullParserException("Unknown tag under " diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index efe4a4c8d..dee52a795 100644 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -100,8 +100,6 @@ public class WifiConfigStore { private static final String XML_TAG_DOCUMENT_HEADER = "WifiConfigStoreData"; private static final String XML_TAG_VERSION = "Version"; private static final String XML_TAG_HEADER_INTEGRITY = "Integrity"; - private static final String XML_TAG_INTEGRITY_ENCRYPTED_DATA = "EncryptedData"; - private static final String XML_TAG_INTEGRITY_IV = "IV"; /** * Current config store data version. This will be incremented for any additions. */ @@ -669,8 +667,7 @@ public class WifiConfigStore { private static void parseAndDiscardIntegrityDataFromXml(XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException { XmlUtil.gotoNextSectionWithName(in, XML_TAG_HEADER_INTEGRITY, outerTagDepth); - XmlUtil.readNextValueWithName(in, XML_TAG_INTEGRITY_ENCRYPTED_DATA); - XmlUtil.readNextValueWithName(in, XML_TAG_INTEGRITY_IV); + XmlUtil.EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1); } /** diff --git a/service/java/com/android/server/wifi/util/XmlUtil.java b/service/java/com/android/server/wifi/util/XmlUtil.java index 188d3b5c7..292c7929a 100644 --- a/service/java/com/android/server/wifi/util/XmlUtil.java +++ b/service/java/com/android/server/wifi/util/XmlUtil.java @@ -16,6 +16,8 @@ package com.android.server.wifi.util; +import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; import android.net.IpConfiguration.ProxySettings; @@ -380,11 +382,13 @@ public class XmlUtil { * 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 out XmlSerializer instance pointing to the XML stream. * @param configuration WifiConfiguration object to be serialized. + * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. */ public static void writeCommonElementsToXml( - XmlSerializer out, WifiConfiguration configuration) + XmlSerializer out, WifiConfiguration configuration, + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { XmlUtil.writeNextValue(out, XML_TAG_CONFIG_KEY, configuration.configKey()); XmlUtil.writeNextValue(out, XML_TAG_SSID, configuration.SSID); @@ -428,7 +432,7 @@ public class XmlUtil { */ public static void writeToXmlForBackup(XmlSerializer out, WifiConfiguration configuration) throws XmlPullParserException, IOException { - writeCommonElementsToXml(out, configuration); + writeCommonElementsToXml(out, configuration, null); XmlUtil.writeNextValue(out, XML_TAG_METERED_OVERRIDE, configuration.meteredOverride); } @@ -436,13 +440,15 @@ public class XmlUtil { * Write the Configuration data elements for config store from the provided Configuration * to the XML stream. * - * @param out XmlSerializer instance pointing 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}. */ public static void writeToXmlForConfigStore( - XmlSerializer out, WifiConfiguration configuration) + XmlSerializer out, WifiConfiguration configuration, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { - writeCommonElementsToXml(out, configuration); + writeCommonElementsToXml(out, configuration, encryptionUtil); XmlUtil.writeNextValue(out, XML_TAG_STATUS, configuration.status); XmlUtil.writeNextValue(out, XML_TAG_FQDN, configuration.FQDN); XmlUtil.writeNextValue( @@ -509,13 +515,16 @@ public class XmlUtil { * Note: This is used for parsing both backup data and config store data. Looping through * the tags make it easy to add or remove elements in the future versions if needed. * - * @param in XmlPullParser instance pointing to the XML stream. + * @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 encryptionUtil Instance of {@link EncryptedDataXmlUtil}. * @return Pair if parsing is successful, * null otherwise. */ public static Pair parseFromXml( - XmlPullParser in, int outerTagDepth) + XmlPullParser in, int outerTagDepth, boolean areCredentialsEncrypted, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { WifiConfiguration configuration = new WifiConfiguration(); String configKeyInData = null; @@ -1022,10 +1031,12 @@ public class XmlUtil { * Write the WifiEnterpriseConfig data elements from the provided config to the XML * stream. * - * @param out XmlSerializer instance pointing to the XML stream. + * @param out XmlSerializer instance pointing to the XML stream. * @param enterpriseConfig WifiEnterpriseConfig object to be serialized. + * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. */ - public static void writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig) + public static void writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { XmlUtil.writeNextValue(out, XML_TAG_IDENTITY, enterpriseConfig.getFieldValue(WifiEnterpriseConfig.IDENTITY_KEY)); @@ -1060,11 +1071,15 @@ public class XmlUtil { /** * Parses the data elements from the provided XML stream to a WifiEnterpriseConfig object. * - * @param in XmlPullParser instance pointing to the XML stream. + * @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 encryptionUtil Instance of {@link EncryptedDataXmlUtil}. * @return WifiEnterpriseConfig object if parsing is successful, null otherwise. */ - public static WifiEnterpriseConfig parseFromXml(XmlPullParser in, int outerTagDepth) + public static WifiEnterpriseConfig parseFromXml(XmlPullParser in, int outerTagDepth, + boolean areCredentialsEncrypted, + @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); @@ -1144,5 +1159,66 @@ public class XmlUtil { return enterpriseConfig; } } + + /** + * Utility class to serialize and deseriaize {@link EncryptedData} object to XML & + * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module. + */ + public static class EncryptedDataXmlUtil { + /** + * List of XML tags corresponding to EncryptedData object elements. + */ + private static final String XML_TAG_ENCRYPTED_DATA = "EncryptedData"; + private static final String XML_TAG_IV = "IV"; + + /** + * Write the NetworkSelectionStatus data elements from the provided status to the XML + * stream. + * + * @param out XmlSerializer instance pointing to the XML stream. + * @param encryptedData EncryptedData object to be serialized. + */ + public static void writeToXml(XmlSerializer out, EncryptedData encryptedData) + throws XmlPullParserException, IOException { + XmlUtil.writeNextValue( + out, XML_TAG_ENCRYPTED_DATA, encryptedData.getEncryptedData()); + XmlUtil.writeNextValue(out, XML_TAG_IV, encryptedData.getIv()); + } + + /** + * Parses the EncryptedData data elements from the provided XML stream to a + * EncryptedData object. + * + * @param in XmlPullParser instance pointing to the XML stream. + * @param outerTagDepth depth of the outer tag in the XML document. + * @return EncryptedData object if parsing is successful, null otherwise. + */ + public static EncryptedData parseFromXml(XmlPullParser in, int outerTagDepth) + throws XmlPullParserException, IOException { + byte[] encryptedData = null; + byte[] iv = null; + + // 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_ENCRYPTED_DATA: + encryptedData = (byte[]) value; + break; + case XML_TAG_IV: + iv = (byte[]) value; + break; + default: + throw new XmlPullParserException( + "Unknown value name found: " + valueName[0]); + } + } + return new EncryptedData(encryptedData, 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 85b4a9370..126a80d3c 100644 --- a/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java +++ b/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java @@ -473,7 +473,8 @@ public class XmlUtilTest { final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); XmlUtil.writeDocumentStart(out, mXmlDocHeader); - WifiConfigurationXmlUtil.writeToXmlForConfigStore(out, configuration); + WifiConfigurationXmlUtil.writeToXmlForConfigStore( + out, configuration, mock(WifiConfigStoreEncryptionUtil.class)); XmlUtil.writeDocumentEnd(out, mXmlDocHeader); return outputStream.toByteArray(); } @@ -485,7 +486,8 @@ public class XmlUtilTest { ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); XmlUtil.gotoDocumentStart(in, mXmlDocHeader); - return WifiConfigurationXmlUtil.parseFromXml(in, in.getDepth()); + return WifiConfigurationXmlUtil.parseFromXml( + in, in.getDepth(), false, mock(WifiConfigStoreEncryptionUtil.class)); } /** @@ -593,7 +595,8 @@ public class XmlUtilTest { final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); out.setOutput(outputStream, StandardCharsets.UTF_8.name()); XmlUtil.writeDocumentStart(out, mXmlDocHeader); - WifiEnterpriseConfigXmlUtil.writeToXml(out, config); + WifiEnterpriseConfigXmlUtil.writeToXml( + out, config, mock(WifiConfigStoreEncryptionUtil.class)); XmlUtil.writeDocumentEnd(out, mXmlDocHeader); return outputStream.toByteArray(); } @@ -604,7 +607,8 @@ public class XmlUtilTest { ByteArrayInputStream inputStream = new ByteArrayInputStream(data); in.setInput(inputStream, StandardCharsets.UTF_8.name()); XmlUtil.gotoDocumentStart(in, mXmlDocHeader); - return WifiEnterpriseConfigXmlUtil.parseFromXml(in, in.getDepth()); + return WifiEnterpriseConfigXmlUtil.parseFromXml( + in, in.getDepth(), false, mock(WifiConfigStoreEncryptionUtil.class)); } private void serializeDeserializeWifiEnterpriseConfig(WifiEnterpriseConfig config) -- cgit v1.2.3 From 09621a42f86690346814c48cf1cdb1f123402e12 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Tue, 22 Oct 2019 16:38:36 -0700 Subject: 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 --- .../com/android/server/wifi/WifiConfigStore.java | 6 - .../android/server/wifi/util/EncryptedData.java | 27 +- .../java/com/android/server/wifi/util/XmlUtil.java | 563 +++++++++++++-------- .../android/server/wifi/WifiConfigStoreTest.java | 8 +- .../com/android/server/wifi/util/XmlUtilTest.java | 67 ++- 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; @@ -378,13 +379,43 @@ 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 if parsing is successful, * null otherwise. */ public static Pair 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) 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) 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) { @@ -1027,6 +1086,35 @@ public class XmlUtil { public static final String XML_TAG_PLMN = "PLMN"; 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. */ @@ -100,6 +111,21 @@ public class XmlUtilTest { serializeDeserializeWifiConfiguration(WifiConfigurationTestUtil.createPskNetwork()); } + /** + * 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. */ @@ -381,6 +407,36 @@ public class XmlUtilTest { serializeDeserializeWifiEnterpriseConfig(config); } + /** + * 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) -- cgit v1.2.3 From a9ebe48227eb5befd221451a013cbd0a76eac999 Mon Sep 17 00:00:00 2001 From: Roshan Pius Date: Tue, 29 Oct 2019 09:15:31 -0700 Subject: WifiConfigStore: Encrypt credentials for networks (4/4) Add a setting to turn on/off encryption. This global setting will be turned on for devices which require encrypted credentials. We don't need to support flipping the global settings back n forth. Only needs to support the one way toggle from off to on once for the lifetime of the device. 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 - adb shell settings put global niap_mode 1 - Ensured that the psk was read correctly on upgrade - Ensured that the psk was encrypted when stored on disk after upgrade Change-Id: Ibabe0814bfc42a7bf610d18e89a7b82bacfdfeed Merged-In: Ibabe0814bfc42a7bf610d18e89a7b82bacfdfeed --- .../wifi/DeletedEphemeralSsidsStoreData.java | 6 ++-- .../com/android/server/wifi/FrameworkFacade.java | 12 +++++++ .../android/server/wifi/NetworkListStoreData.java | 14 ++++---- .../server/wifi/NetworkRequestStoreData.java | 6 ++-- .../server/wifi/NetworkSuggestionStoreData.java | 18 +++++----- .../server/wifi/RandomizedMacStoreData.java | 6 ++-- .../com/android/server/wifi/SsidSetStoreData.java | 6 ++-- .../android/server/wifi/WakeupConfigStoreData.java | 6 ++-- .../com/android/server/wifi/WifiConfigManager.java | 10 +++--- .../com/android/server/wifi/WifiConfigStore.java | 41 ++++++++++++++++------ .../java/com/android/server/wifi/WifiInjector.java | 2 +- .../hotspot2/PasspointConfigSharedStoreData.java | 6 ++-- .../hotspot2/PasspointConfigUserStoreData.java | 6 ++-- .../java/com/android/server/wifi/util/XmlUtil.java | 15 ++++---- .../android/server/wifi/WifiConfigManagerTest.java | 2 +- .../com/android/server/wifi/util/XmlUtilTest.java | 6 ++-- 16 files changed, 97 insertions(+), 65 deletions(-) diff --git a/service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java b/service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java index 3575ff254..b71d5a023 100644 --- a/service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java +++ b/service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java @@ -16,7 +16,7 @@ package com.android.server.wifi; -import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; @@ -48,7 +48,7 @@ public class DeletedEphemeralSsidsStoreData implements WifiConfigStore.StoreData @Override public void serializeData(XmlSerializer out, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { if (mSsidToTimeMap != null) { XmlUtil.writeNextValue(out, XML_TAG_SSID_LIST, mSsidToTimeMap); @@ -58,7 +58,7 @@ public class DeletedEphemeralSsidsStoreData implements WifiConfigStore.StoreData @Override public void deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/FrameworkFacade.java b/service/java/com/android/server/wifi/FrameworkFacade.java index f3c5d4b3d..4fbe31867 100644 --- a/service/java/com/android/server/wifi/FrameworkFacade.java +++ b/service/java/com/android/server/wifi/FrameworkFacade.java @@ -45,6 +45,11 @@ import com.android.server.wifi.util.WifiAsyncChannel; */ public class FrameworkFacade { public static final String TAG = "FrameworkFacade"; + /** + * NIAP global settings flag. + * Note: This should be added to {@link android.provider.Settings.Global}. + */ + private static final String NIAP_MODE_SETTINGS_NAME = "niap_mode"; private ActivityManagerInternal mActivityManagerInternal; @@ -82,6 +87,13 @@ public class FrameworkFacade { return Settings.Secure.getString(context.getContentResolver(), name); } + /** + * Returns whether the device is in NIAP mode or not. + */ + public boolean isNiapModeOn(Context context) { + return getIntegerSetting(context, NIAP_MODE_SETTINGS_NAME, 0) == 1; + } + /** * Helper method for classes to register a ContentObserver * {@see ContentResolver#registerContentObserver(Uri,boolean,ContentObserver)}. diff --git a/service/java/com/android/server/wifi/NetworkListStoreData.java b/service/java/com/android/server/wifi/NetworkListStoreData.java index 4f2f36b9b..52e655b1e 100644 --- a/service/java/com/android/server/wifi/NetworkListStoreData.java +++ b/service/java/com/android/server/wifi/NetworkListStoreData.java @@ -18,7 +18,7 @@ package com.android.server.wifi; import static com.android.server.wifi.WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION; -import android.annotation.NonNull; +import android.annotation.Nullable; import android.content.Context; import android.net.IpConfiguration; import android.net.wifi.WifiConfiguration; @@ -71,7 +71,7 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData @Override public void serializeData(XmlSerializer out, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { serializeNetworkList(out, mConfigurations, encryptionUtil); } @@ -79,7 +79,7 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData @Override public void deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { @@ -130,7 +130,7 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData * @throws IOException */ private void serializeNetworkList(XmlSerializer out, List networkList, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { if (networkList == null) { return; @@ -150,7 +150,7 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData * @throws IOException */ private void serializeNetwork(XmlSerializer out, WifiConfiguration config, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK); @@ -194,7 +194,7 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData */ private List parseNetworkList(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { List networkList = new ArrayList<>(); while (XmlUtil.gotoNextSectionWithNameOrEnd(in, XML_TAG_SECTION_HEADER_NETWORK, @@ -226,7 +226,7 @@ public abstract class NetworkListStoreData implements WifiConfigStore.StoreData */ private WifiConfiguration parseNetwork(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { Pair parsedConfig = null; NetworkSelectionStatus status = null; diff --git a/service/java/com/android/server/wifi/NetworkRequestStoreData.java b/service/java/com/android/server/wifi/NetworkRequestStoreData.java index 3a5143f56..7457079ae 100644 --- a/service/java/com/android/server/wifi/NetworkRequestStoreData.java +++ b/service/java/com/android/server/wifi/NetworkRequestStoreData.java @@ -16,7 +16,7 @@ package com.android.server.wifi; -import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.MacAddress; import android.util.Log; @@ -90,7 +90,7 @@ public class NetworkRequestStoreData implements WifiConfigStore.StoreData { @Override public void serializeData(XmlSerializer out, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { serializeApprovedAccessPointsMap(out, mDataSource.toSerialize()); } @@ -98,7 +98,7 @@ public class NetworkRequestStoreData implements WifiConfigStore.StoreData { @Override public void deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java b/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java index fc0c55b5a..e973bdbe2 100644 --- a/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java +++ b/service/java/com/android/server/wifi/NetworkSuggestionStoreData.java @@ -18,7 +18,7 @@ package com.android.server.wifi; import static com.android.server.wifi.WifiConfigStore.ENCRYPT_CREDENTIALS_CONFIG_STORE_DATA_VERSION; -import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.wifi.WifiConfiguration; import android.net.wifi.WifiEnterpriseConfig; import android.net.wifi.WifiNetworkSuggestion; @@ -103,7 +103,7 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { @Override public void serializeData(XmlSerializer out, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { serializeNetworkSuggestionsMap(out, mDataSource.toSerialize(), encryptionUtil); } @@ -111,7 +111,7 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { @Override public void deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { @@ -149,7 +149,7 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { */ private void serializeNetworkSuggestionsMap( XmlSerializer out, final Map networkSuggestionsMap, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { if (networkSuggestionsMap == null) { return; @@ -177,7 +177,7 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { */ private void serializeExtNetworkSuggestions( XmlSerializer out, final Set extNetworkSuggestions, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { for (ExtendedWifiNetworkSuggestion extNetworkSuggestion : extNetworkSuggestions) { serializeNetworkSuggestion(out, extNetworkSuggestion.wns, encryptionUtil); @@ -192,7 +192,7 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { */ private void serializeNetworkSuggestion(XmlSerializer out, final WifiNetworkSuggestion suggestion, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_NETWORK_SUGGESTION); @@ -232,7 +232,7 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { */ private Map parseNetworkSuggestionsMap(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { Map networkSuggestionsMap = new HashMap<>(); while (XmlUtil.gotoNextSectionWithNameOrEnd( @@ -269,7 +269,7 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { */ private Set parseExtNetworkSuggestions( XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil, PerAppInfo perAppInfo) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, PerAppInfo perAppInfo) throws XmlPullParserException, IOException { Set extNetworkSuggestions = new HashSet<>(); while (XmlUtil.gotoNextSectionWithNameOrEnd( @@ -297,7 +297,7 @@ public class NetworkSuggestionStoreData implements WifiConfigStore.StoreData { */ private WifiNetworkSuggestion parseNetworkSuggestion(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { Pair parsedConfig = null; WifiEnterpriseConfig enterpriseConfig = null; diff --git a/service/java/com/android/server/wifi/RandomizedMacStoreData.java b/service/java/com/android/server/wifi/RandomizedMacStoreData.java index 8e47ee7bf..ecbd7177f 100644 --- a/service/java/com/android/server/wifi/RandomizedMacStoreData.java +++ b/service/java/com/android/server/wifi/RandomizedMacStoreData.java @@ -16,7 +16,7 @@ package com.android.server.wifi; -import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; import com.android.server.wifi.util.XmlUtil; @@ -44,7 +44,7 @@ public class RandomizedMacStoreData implements WifiConfigStore.StoreData { @Override public void serializeData(XmlSerializer out, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { if (mMacMapping != null) { XmlUtil.writeNextValue(out, XML_TAG_MAC_MAP, mMacMapping); @@ -54,7 +54,7 @@ public class RandomizedMacStoreData implements WifiConfigStore.StoreData { @Override public void deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/SsidSetStoreData.java b/service/java/com/android/server/wifi/SsidSetStoreData.java index 1339dae38..36b547cd2 100644 --- a/service/java/com/android/server/wifi/SsidSetStoreData.java +++ b/service/java/com/android/server/wifi/SsidSetStoreData.java @@ -16,7 +16,7 @@ package com.android.server.wifi; -import android.annotation.NonNull; +import android.annotation.Nullable; import android.text.TextUtils; import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; @@ -77,7 +77,7 @@ public class SsidSetStoreData implements WifiConfigStore.StoreData { @Override public void serializeData(XmlSerializer out, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { Set ssidSet = mDataSource.getSsids(); if (ssidSet != null && !ssidSet.isEmpty()) { @@ -88,7 +88,7 @@ public class SsidSetStoreData implements WifiConfigStore.StoreData { @Override public void deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/WakeupConfigStoreData.java b/service/java/com/android/server/wifi/WakeupConfigStoreData.java index 1d146a0e1..847d8fbbc 100644 --- a/service/java/com/android/server/wifi/WakeupConfigStoreData.java +++ b/service/java/com/android/server/wifi/WakeupConfigStoreData.java @@ -16,7 +16,7 @@ package com.android.server.wifi; -import android.annotation.NonNull; +import android.annotation.Nullable; import android.util.ArraySet; import android.util.Log; @@ -97,7 +97,7 @@ public class WakeupConfigStoreData implements StoreData { @Override public void serializeData(XmlSerializer out, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { writeFeatureState(out); @@ -146,7 +146,7 @@ public class WakeupConfigStoreData implements StoreData { @Override public void deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { if (!mHasBeenRead) { Log.d(TAG, "WifiWake user data has been read"); diff --git a/service/java/com/android/server/wifi/WifiConfigManager.java b/service/java/com/android/server/wifi/WifiConfigManager.java index d1734d445..533155d0c 100644 --- a/service/java/com/android/server/wifi/WifiConfigManager.java +++ b/service/java/com/android/server/wifi/WifiConfigManager.java @@ -3131,7 +3131,8 @@ public class WifiConfigManager { if (mDeferredUserUnlockRead) { Log.i(TAG, "Handling user unlock before loading from store."); List userStoreFiles = - WifiConfigStore.createUserFiles(mCurrentUserId); + WifiConfigStore.createUserFiles( + mCurrentUserId, mFrameworkFacade.isNiapModeOn(mContext)); if (userStoreFiles == null) { Log.wtf(TAG, "Failed to create user store files"); return false; @@ -3170,7 +3171,8 @@ public class WifiConfigManager { private boolean loadFromUserStoreAfterUnlockOrSwitch(int userId) { try { List userStoreFiles = - WifiConfigStore.createUserFiles(userId); + WifiConfigStore.createUserFiles( + userId, mFrameworkFacade.isNiapModeOn(mContext)); if (userStoreFiles == null) { Log.e(TAG, "Failed to create user store files"); return false; @@ -3180,8 +3182,8 @@ public class WifiConfigManager { Log.wtf(TAG, "Reading from new store failed. All saved private networks are lost!", e); return false; } catch (XmlPullParserException e) { - Log.wtf(TAG, "XML deserialization of store failed. All saved private networks are" + - "lost!", e); + Log.wtf(TAG, "XML deserialization of store failed. All saved private networks are " + + "lost!", e); return false; } loadInternalDataFromUserStore(mNetworkListUserStoreData.getConfigurations(), diff --git a/service/java/com/android/server/wifi/WifiConfigStore.java b/service/java/com/android/server/wifi/WifiConfigStore.java index 350e8b52f..42d9f82cb 100644 --- a/service/java/com/android/server/wifi/WifiConfigStore.java +++ b/service/java/com/android/server/wifi/WifiConfigStore.java @@ -61,6 +61,7 @@ import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.stream.Collectors; +import java.util.stream.Stream; /** * This class provides a mechanism to save data to persistent store files {@link StoreFile}. @@ -287,9 +288,11 @@ public class WifiConfigStore { * @param storeBaseDir Base directory under which the store file is to be stored. The store file * will be at /wifi/WifiConfigStore.xml. * @param fileId Identifier for the file. See {@link StoreFileId}. + * @param shouldEncryptCredentials Whether to encrypt credentials or not. * @return new instance of the store file or null if the directory cannot be created. */ - private static @Nullable StoreFile createFile(File storeBaseDir, @StoreFileId int fileId) { + private static @Nullable StoreFile createFile(File storeBaseDir, @StoreFileId int fileId, + boolean shouldEncryptCredentials) { File storeDir = new File(storeBaseDir, STORE_DIRECTORY_NAME); if (!storeDir.exists()) { if (!storeDir.mkdir()) { @@ -298,18 +301,22 @@ public class WifiConfigStore { } } File file = new File(storeDir, STORE_ID_TO_FILE_NAME.get(fileId)); - WifiConfigStoreEncryptionUtil encryptionUtil = - new WifiConfigStoreEncryptionUtil(file.getName()); + WifiConfigStoreEncryptionUtil encryptionUtil = null; + if (shouldEncryptCredentials) { + encryptionUtil = new WifiConfigStoreEncryptionUtil(file.getName()); + } return new StoreFile(file, fileId, encryptionUtil); } /** * Create a new instance of the shared store file. * + * @param shouldEncryptCredentials Whether to encrypt credentials or not. * @return new instance of the store file or null if the directory cannot be created. */ - public static @Nullable StoreFile createSharedFile() { - return createFile(Environment.getDataMiscDirectory(), STORE_FILE_SHARED_GENERAL); + public static @Nullable StoreFile createSharedFile(boolean shouldEncryptCredentials) { + return createFile(Environment.getDataMiscDirectory(), STORE_FILE_SHARED_GENERAL, + shouldEncryptCredentials); } /** @@ -317,14 +324,18 @@ public class WifiConfigStore { * The user store file is inside the user's encrypted data directory. * * @param userId userId corresponding to the currently logged-in user. + * @param shouldEncryptCredentials Whether to encrypt credentials or not. * @return List of new instances of the store files created or null if the directory cannot be * created. */ - public static @Nullable List createUserFiles(int userId) { + public static @Nullable List createUserFiles(int userId, + boolean shouldEncryptCredentials) { List storeFiles = new ArrayList<>(); for (int fileId : Arrays.asList( STORE_FILE_USER_GENERAL, STORE_FILE_USER_NETWORK_SUGGESTIONS)) { - StoreFile storeFile = createFile(Environment.getDataMiscCeDirectory(userId), fileId); + StoreFile storeFile = + createFile(Environment.getDataMiscCeDirectory(userId), fileId, + shouldEncryptCredentials); if (storeFile == null) { return null; } @@ -669,6 +680,13 @@ public class WifiConfigStore { */ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { pw.println("Dump of WifiConfigStore"); + pw.println("WifiConfigStore - Store File Begin ----"); + Stream.of(Arrays.asList(mSharedStore), mUserStores) + .flatMap(List::stream) + .forEach((storeFile) -> { + pw.print("Name: " + storeFile.mFileName); + pw.println(", Credentials encrypted: " + storeFile.getEncryptionUtil() != null); + }); pw.println("WifiConfigStore - Store Data Begin ----"); for (StoreData storeData : mStoreDataList) { pw.print("StoreData =>"); @@ -716,7 +734,7 @@ public class WifiConfigStore { private final WifiConfigStoreEncryptionUtil mEncryptionUtil; public StoreFile(File file, @StoreFileId int fileId, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) { + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) { mAtomicFile = new AtomicFile(file); mFileName = file.getAbsolutePath(); mFileId = fileId; @@ -735,7 +753,7 @@ public class WifiConfigStore { /** * @return Returns the encryption util used for this store file. */ - public @NonNull WifiConfigStoreEncryptionUtil getEncryptionUtil() { + public @Nullable WifiConfigStoreEncryptionUtil getEncryptionUtil() { return mEncryptionUtil; } @@ -813,7 +831,8 @@ public class WifiConfigStore { * @param out The output stream to serialize the data to * @param encryptionUtil Utility to help encrypt any credential data. */ - void serializeData(XmlSerializer out, @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + void serializeData(XmlSerializer out, + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException; /** @@ -829,7 +848,7 @@ public class WifiConfigStore { * in the store for them. */ void deserializeData(@Nullable XmlPullParser in, int outerTagDepth, @Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException; /** diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index fe9ebea17..f7212ddfc 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -241,7 +241,7 @@ public class WifiInjector { mWifiKeyStore = new WifiKeyStore(mKeyStore); mWifiConfigStore = new WifiConfigStore( mContext, clientModeImplLooper, mClock, mWifiMetrics, - WifiConfigStore.createSharedFile()); + WifiConfigStore.createSharedFile(mFrameworkFacade.isNiapModeOn(mContext))); SubscriptionManager subscriptionManager = mContext.getSystemService(SubscriptionManager.class); // Config Manager diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreData.java b/service/java/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreData.java index 9abccb94b..7f5a6b408 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreData.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreData.java @@ -16,7 +16,7 @@ package com.android.server.wifi.hotspot2; -import android.annotation.NonNull; +import android.annotation.Nullable; import com.android.server.wifi.WifiConfigStore; import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; @@ -76,7 +76,7 @@ public class PasspointConfigSharedStoreData implements WifiConfigStore.StoreData @Override public void serializeData(XmlSerializer out, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { serializeShareData(out); } @@ -84,7 +84,7 @@ public class PasspointConfigSharedStoreData implements WifiConfigStore.StoreData @Override public void deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java b/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java index 1001b1189..123cf8982 100644 --- a/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java +++ b/service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java @@ -16,7 +16,7 @@ package com.android.server.wifi.hotspot2; -import android.annotation.NonNull; +import android.annotation.Nullable; import android.net.wifi.hotspot2.PasspointConfiguration; import android.text.TextUtils; @@ -106,7 +106,7 @@ public class PasspointConfigUserStoreData implements WifiConfigStore.StoreData { @Override public void serializeData(XmlSerializer out, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { serializeUserData(out); } @@ -114,7 +114,7 @@ public class PasspointConfigUserStoreData implements WifiConfigStore.StoreData { @Override public void deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { // Ignore empty reads. if (in == null) { diff --git a/service/java/com/android/server/wifi/util/XmlUtil.java b/service/java/com/android/server/wifi/util/XmlUtil.java index 6128b0b4c..db0f4289b 100644 --- a/service/java/com/android/server/wifi/util/XmlUtil.java +++ b/service/java/com/android/server/wifi/util/XmlUtil.java @@ -16,7 +16,6 @@ package com.android.server.wifi.util; -import android.annotation.NonNull; import android.annotation.Nullable; import android.net.IpConfiguration; import android.net.IpConfiguration.IpAssignment; @@ -477,7 +476,7 @@ public class XmlUtil { */ public static void writeToXmlForConfigStore( XmlSerializer out, WifiConfiguration configuration, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { writeCommonElementsToXml(out, configuration, encryptionUtil); XmlUtil.writeNextValue(out, XML_TAG_STATUS, configuration.status); @@ -555,7 +554,7 @@ public class XmlUtil { */ public static Pair parseFromXml( XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { WifiConfiguration configuration = new WifiConfiguration(); String configKeyInData = null; @@ -715,7 +714,7 @@ public class XmlUtil { } switch (tagName) { case XML_TAG_PRE_SHARED_KEY: - if (!shouldExpectEncryptedCredentials) { + if (!shouldExpectEncryptedCredentials || encryptionUtil == null) { throw new XmlPullParserException( "Encrypted preSharedKey section not expected"); } @@ -1094,7 +1093,7 @@ public class XmlUtil { */ private static void writePasswordToXml( XmlSerializer out, String password, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { EncryptedData encryptedData = null; if (encryptionUtil != null) { @@ -1124,7 +1123,7 @@ public class XmlUtil { * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. */ public static void writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { XmlUtil.writeNextValue(out, XML_TAG_IDENTITY, enterpriseConfig.getFieldValue(WifiEnterpriseConfig.IDENTITY_KEY)); @@ -1168,7 +1167,7 @@ public class XmlUtil { */ public static WifiEnterpriseConfig parseFromXml(XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, - @NonNull WifiConfigStoreEncryptionUtil encryptionUtil) + @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) throws XmlPullParserException, IOException { WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig(); @@ -1260,7 +1259,7 @@ public class XmlUtil { } switch (tagName) { case XML_TAG_PASSWORD: - if (!shouldExpectEncryptedCredentials) { + if (!shouldExpectEncryptedCredentials || encryptionUtil == null) { throw new XmlPullParserException( "encrypted password section not expected"); } diff --git a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java index 0badc6fbd..c4cbc6e50 100644 --- a/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java +++ b/tests/wifitests/src/com/android/server/wifi/WifiConfigManagerTest.java @@ -234,7 +234,7 @@ public class WifiConfigManagerTest { .spyStatic(WifiConfigurationUtil.class) .strictness(Strictness.LENIENT) .startMocking(); - when(WifiConfigStore.createUserFiles(anyInt())).thenReturn(mock(List.class)); + when(WifiConfigStore.createUserFiles(anyInt(), anyBoolean())).thenReturn(mock(List.class)); when(mTelephonyManager.createForSubscriptionId(anyInt())).thenReturn(mDataTelephonyManager); when(WifiConfigurationUtil.calculatePersistentMacForConfiguration(any(), any())) .thenReturn(TEST_RANDOMIZED_MAC); 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 66534d247..8f96bc106 100644 --- a/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java +++ b/tests/wifitests/src/com/android/server/wifi/util/XmlUtilTest.java @@ -37,8 +37,6 @@ 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; @@ -77,7 +75,7 @@ public class XmlUtilTest { private static final int TEST_PHASE2_METHOD = WifiEnterpriseConfig.Phase2.MSCHAPV2; private final String mXmlDocHeader = "XmlUtilTest"; - @Mock private WifiConfigStoreEncryptionUtil mWifiConfigStoreEncryptionUtil; + private WifiConfigStoreEncryptionUtil mWifiConfigStoreEncryptionUtil = null; @Before public void setUp() throws Exception { @@ -117,6 +115,7 @@ public class XmlUtilTest { @Test public void testPskWifiConfigurationSerializeDeserializeWithEncryption() throws IOException, XmlPullParserException { + mWifiConfigStoreEncryptionUtil = mock(WifiConfigStoreEncryptionUtil.class); WifiConfiguration pskNetwork = WifiConfigurationTestUtil.createPskNetwork(); EncryptedData encryptedData = new EncryptedData(new byte[0], new byte[0]); when(mWifiConfigStoreEncryptionUtil.encrypt(pskNetwork.preSharedKey.getBytes())) @@ -429,6 +428,7 @@ public class XmlUtilTest { config.setEapMethod(TEST_EAP_METHOD); config.setPhase2Method(TEST_PHASE2_METHOD); + mWifiConfigStoreEncryptionUtil = mock(WifiConfigStoreEncryptionUtil.class); EncryptedData encryptedData = new EncryptedData(new byte[0], new byte[0]); when(mWifiConfigStoreEncryptionUtil.encrypt(TEST_PASSWORD.getBytes())) .thenReturn(encryptedData); -- cgit v1.2.3