summaryrefslogtreecommitdiff
path: root/service
diff options
context:
space:
mode:
authorRoshan Pius <rpius@google.com>2019-10-22 13:42:45 -0700
committerRoshan Pius <rpius@google.com>2019-11-14 11:18:00 -0800
commita161d62d9baac95a087cb3252d51c1fd101d24fa (patch)
tree4213efe8d35f12e1bd993bc35931b322a4da8f74 /service
parentbc8fa0c163c40afa999ac71cc78687bb845131ab (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
Diffstat (limited to 'service')
-rw-r--r--service/java/com/android/server/wifi/DeletedEphemeralSsidsStoreData.java10
-rw-r--r--service/java/com/android/server/wifi/NetworkListStoreData.java9
-rw-r--r--service/java/com/android/server/wifi/NetworkRequestStoreData.java9
-rw-r--r--service/java/com/android/server/wifi/NetworkSuggestionStoreData.java9
-rw-r--r--service/java/com/android/server/wifi/RandomizedMacStoreData.java10
-rw-r--r--service/java/com/android/server/wifi/SsidSetStoreData.java9
-rw-r--r--service/java/com/android/server/wifi/WakeupConfigStoreData.java9
-rw-r--r--service/java/com/android/server/wifi/WifiConfigStore.java209
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointConfigSharedStoreData.java10
-rw-r--r--service/java/com/android/server/wifi/hotspot2/PasspointConfigUserStoreData.java9
-rw-r--r--service/java/com/android/server/wifi/util/WifiConfigStoreEncryptionUtil.java (renamed from service/java/com/android/server/wifi/util/DataIntegrityChecker.java)139
11 files changed, 156 insertions, 276 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");
}
}
+
}