diff options
author | Roshan Pius <rpius@google.com> | 2019-10-22 13:42:45 -0700 |
---|---|---|
committer | Roshan Pius <rpius@google.com> | 2019-11-14 11:18:00 -0800 |
commit | a161d62d9baac95a087cb3252d51c1fd101d24fa (patch) | |
tree | 4213efe8d35f12e1bd993bc35931b322a4da8f74 | |
parent | bc8fa0c163c40afa999ac71cc78687bb845131ab (diff) |
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
24 files changed, 263 insertions, 615 deletions
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<String> 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): - * <?xml version='1.0' encoding='utf-8' standalone='yes' ?> - * <WifiConfigStoreData> - * <int name="Version" value="2" /> - * <Integrity> - * <byte-array name="EncryptedData" num="48">!EncryptedData!</byte-array> - * <byte-array name="IV" num="12">!IV!</byte-array> - * </Integrity> - */ - 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<StoreData> storeDataSet) + private void indicateNoDataForStoreDatas(Collection<StoreData> 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<StoreData> 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<StoreData> 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; } /** @@ -810,6 +742,13 @@ public class WifiConfigStore { } /** + * @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. * * @return raw data read from the file or null if the file is not found or the data has @@ -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/WifiConfigStoreEncryptionUtil.java index 6f03a4861..2f9b08f2b 100644 --- a/service/java/com/android/server/wifi/util/DataIntegrityChecker.java +++ b/service/java/com/android/server/wifi/util/WifiConfigStoreEncryptionUtil.java @@ -17,22 +17,22 @@ 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.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; @@ -43,34 +43,26 @@ import javax.crypto.SecretKey; import javax.crypto.spec.GCMParameterSpec; /** - * Tools to provide integrity checking of byte arrays based on NIAP Common Criteria Protection - * Profile <a href="https://www.niap-ccevs.org/MMO/PP/-417-/#FCS_STG_EXT.3.1">FCS_STG_EXT.3.1</a>. + * Tools to help encrypt/decrypt */ -public class DataIntegrityChecker { - private static final String TAG = "DataIntegrityChecker"; +public class WifiConfigStoreEncryptionUtil { + private static final String TAG = "WifiConfigStoreEncryptionUtil"; - private static final String ALIAS_SUFFIX = ".data-integrity-checker-key"; + private static final String ALIAS_SUFFIX = ".data-encryption-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. + * 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 for which integrity check is performed. + * @param dataFileName The full path of the data file. * @throws NullPointerException When data file is empty string. */ - public DataIntegrityChecker(@NonNull String dataFileName) { + public WifiConfigStoreEncryptionUtil(@NonNull String dataFileName) { if (TextUtils.isEmpty(dataFileName)) { throw new NullPointerException("dataFileName must not be null or the empty " + "string"); @@ -83,80 +75,16 @@ public class DataIntegrityChecker { } /** - * 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. + * Encrypt the provided data blob. * - * @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|. + * @param data Data blob to be encrypted. + * @return Instance of {@link EncryptedData} containing the encrypted info. */ - 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) { + public @Nullable EncryptedData encrypt(byte[] data) { EncryptedData encryptedData = null; try { Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM); - SecretKey secretKeyReference = getOrCreateSecretKey(keyAlias); + SecretKey secretKeyReference = getOrCreateSecretKey(getKeyAlias()); if (secretKeyReference != null) { cipher.init(Cipher.ENCRYPT_MODE, secretKeyReference); encryptedData = new EncryptedData(cipher.doFinal(data), cipher.getIV()); @@ -178,12 +106,18 @@ public class DataIntegrityChecker { return encryptedData; } - private byte[] decrypt(EncryptedData encryptedData, String keyAlias) { + /** + * 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(keyAlias); + SecretKey secretKeyReference = getOrCreateSecretKey(getKeyAlias()); if (secretKeyReference != null) { cipher.init(Cipher.DECRYPT_MODE, secretKeyReference, spec); decryptedData = cipher.doFinal(encryptedData.getEncryptedData()); @@ -207,8 +141,7 @@ public class DataIntegrityChecker { private SecretKey getOrCreateSecretKey(String keyAlias) { SecretKey secretKey = null; try { - KeyStore keyStore = KeyStore.getInstance(KEY_STORE); - keyStore.load(null); + 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); @@ -227,17 +160,14 @@ public class DataIntegrityChecker { 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 (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) { @@ -250,22 +180,6 @@ public class DataIntegrityChecker { 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) { @@ -275,4 +189,5 @@ public class DataIntegrityChecker { 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 = "<?xml version='1.0' encoding='utf-8' standalone='yes' ?>\n" + "<WifiConfigStoreData>\n" - + "<int name=\"Version\" value=\"2\" />\n" - + "<Integrity>\n" - + "<byte-array name=\"EncryptedData\" num=\"48\">000000000000000000000000000000" - + "000000000000000000000000000000000000000000000000000000000000000000" - + "</byte-array>\n" - + "<byte-array name=\"IV\" num=\"12\">000000000000000000000000</byte-array>\n" - + "</Integrity>\n" + + "<int name=\"Version\" value=\"3\" />\n" + "<NetworkList>\n" + "<Network>\n" + "<WifiConfiguration>\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<EncryptedData> integrityCaptor = - ArgumentCaptor.forClass(EncryptedData.class); - ArgumentCaptor<byte[]> 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)); - } -} |