1 /*
2  * Copyright (C) 2016 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.wifi.util;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.app.compat.CompatChanges;
22 import android.net.InetAddresses;
23 import android.net.IpConfiguration;
24 import android.net.IpConfiguration.IpAssignment;
25 import android.net.IpConfiguration.ProxySettings;
26 import android.net.LinkAddress;
27 import android.net.MacAddress;
28 import android.net.ProxyInfo;
29 import android.net.RouteInfo;
30 import android.net.StaticIpConfiguration;
31 import android.net.Uri;
32 import android.net.wifi.OuiKeyedData;
33 import android.net.wifi.ScanResult;
34 import android.net.wifi.SecurityParams;
35 import android.net.wifi.SoftApConfiguration;
36 import android.net.wifi.WifiConfiguration;
37 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
38 import android.net.wifi.WifiEnterpriseConfig;
39 import android.net.wifi.WifiManager;
40 import android.net.wifi.WifiMigration;
41 import android.net.wifi.WifiSsid;
42 import android.os.ParcelUuid;
43 import android.os.PersistableBundle;
44 import android.text.TextUtils;
45 import android.util.Log;
46 import android.util.Pair;
47 import android.util.SparseIntArray;
48 
49 import com.android.modules.utils.build.SdkLevel;
50 
51 import org.xmlpull.v1.XmlPullParser;
52 import org.xmlpull.v1.XmlPullParserException;
53 import org.xmlpull.v1.XmlSerializer;
54 
55 import java.io.ByteArrayInputStream;
56 import java.io.ByteArrayOutputStream;
57 import java.io.IOException;
58 import java.net.Inet4Address;
59 import java.net.InetAddress;
60 import java.nio.charset.StandardCharsets;
61 import java.util.ArrayList;
62 import java.util.Arrays;
63 import java.util.BitSet;
64 import java.util.Collections;
65 import java.util.HashMap;
66 import java.util.List;
67 import java.util.Locale;
68 
69 /**
70  * Utils for manipulating XML data. This is essentially a wrapper over XmlUtils provided by core.
71  * The utility provides methods to write/parse section headers and write/parse values.
72  * This utility is designed for formatting the XML into the following format:
73  * <Document Header>
74  *  <Section 1 Header>
75  *   <Value 1>
76  *   <Value 2>
77  *   ...
78  *   <Sub Section 1 Header>
79  *    <Value 1>
80  *    <Value 2>
81  *    ...
82  *   </Sub Section 1 Header>
83  *  </Section 1 Header>
84  * </Document Header>
85  *
86  * Note: These utility methods are meant to be used for:
87  * 1. Backup/restore wifi network data to/from cloud.
88  * 2. Persisting wifi network data to/from disk.
89  */
90 public class XmlUtil {
91     private static final String TAG = "WifiXmlUtil";
92 
93     public static final String XML_TAG_VENDOR_DATA_LIST = "VendorDataList";
94     public static final String XML_TAG_OUI_KEYED_DATA = "OuiKeyedData";
95     public static final String XML_TAG_VENDOR_DATA_OUI = "VendorDataOui";
96     public static final String XML_TAG_PERSISTABLE_BUNDLE = "PersistableBundle";
97 
98     /**
99      * Ensure that the XML stream is at a start tag or the end of document.
100      *
101      * @throws XmlPullParserException if parsing errors occur.
102      */
gotoStartTag(XmlPullParser in)103     private static void gotoStartTag(XmlPullParser in)
104             throws XmlPullParserException, IOException {
105         int type = in.getEventType();
106         while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) {
107             type = in.next();
108         }
109     }
110 
111     /**
112      * Ensure that the XML stream is at an end tag or the end of document.
113      *
114      * @throws XmlPullParserException if parsing errors occur.
115      */
gotoEndTag(XmlPullParser in)116     private static void gotoEndTag(XmlPullParser in)
117             throws XmlPullParserException, IOException {
118         int type = in.getEventType();
119         while (type != XmlPullParser.END_TAG && type != XmlPullParser.END_DOCUMENT) {
120             type = in.next();
121         }
122     }
123 
124     /**
125      * Start processing the XML stream at the document header.
126      *
127      * @param in         XmlPullParser instance pointing to the XML stream.
128      * @param headerName expected name for the start tag.
129      * @throws XmlPullParserException if parsing errors occur.
130      */
gotoDocumentStart(XmlPullParser in, String headerName)131     public static void gotoDocumentStart(XmlPullParser in, String headerName)
132             throws XmlPullParserException, IOException {
133         XmlUtilHelper.beginDocument(in, headerName);
134     }
135 
136     /**
137      * Move the XML stream to the next section header or indicate if there are no more sections.
138      * The provided outerDepth is used to find sub sections within that depth.
139      *
140      * Use this to move across sections if the ordering of sections are variable. The returned name
141      * can be used to decide what section is next.
142      *
143      * @param in         XmlPullParser instance pointing to the XML stream.
144      * @param headerName An array of one string, used to return the name of the next section.
145      * @param outerDepth Find section within this depth.
146      * @return {@code true} if a next section is found, {@code false} if there are no more sections.
147      * @throws XmlPullParserException if parsing errors occur.
148      */
gotoNextSectionOrEnd( XmlPullParser in, String[] headerName, int outerDepth)149     public static boolean gotoNextSectionOrEnd(
150             XmlPullParser in, String[] headerName, int outerDepth)
151             throws XmlPullParserException, IOException {
152         if (XmlUtilHelper.nextElementWithin(in, outerDepth)) {
153             headerName[0] = in.getName();
154             return true;
155         }
156         return false;
157     }
158 
159     /**
160      * Move the XML stream to the next section header or indicate if there are no more sections.
161      * If a section, exists ensure that the name matches the provided name.
162      * The provided outerDepth is used to find sub sections within that depth.
163      *
164      * Use this to move across repeated sections until the end.
165      *
166      * @param in           XmlPullParser instance pointing to the XML stream.
167      * @param expectedName expected name for the section header.
168      * @param outerDepth   Find section within this depth.
169      * @return {@code true} if a next section is found, {@code false} if there are no more sections.
170      * @throws XmlPullParserException if the section header name does not match |expectedName|,
171      *                                or if parsing errors occur.
172      */
gotoNextSectionWithNameOrEnd( XmlPullParser in, String expectedName, int outerDepth)173     public static boolean gotoNextSectionWithNameOrEnd(
174             XmlPullParser in, String expectedName, int outerDepth)
175             throws XmlPullParserException, IOException {
176         String[] headerName = new String[1];
177         if (gotoNextSectionOrEnd(in, headerName, outerDepth)) {
178             if (headerName[0].equals(expectedName)) {
179                 return true;
180             }
181             throw new XmlPullParserException(
182                     "Next section name does not match expected name: " + expectedName);
183         }
184         return false;
185     }
186 
187     /**
188      * Move the XML stream to the next section header and ensure that the name matches the provided
189      * name.
190      * The provided outerDepth is used to find sub sections within that depth.
191      *
192      * Use this to move across sections if the ordering of sections are fixed.
193      *
194      * @param in           XmlPullParser instance pointing to the XML stream.
195      * @param expectedName expected name for the section header.
196      * @param outerDepth   Find section within this depth.
197      * @throws XmlPullParserException if the section header name does not match |expectedName|,
198      *                                there are no more sections or if parsing errors occur.
199      */
gotoNextSectionWithName( XmlPullParser in, String expectedName, int outerDepth)200     public static void gotoNextSectionWithName(
201             XmlPullParser in, String expectedName, int outerDepth)
202             throws XmlPullParserException, IOException {
203         if (!gotoNextSectionWithNameOrEnd(in, expectedName, outerDepth)) {
204             throw new XmlPullParserException("Section not found. Expected: " + expectedName);
205         }
206     }
207 
208     /**
209      * Checks if the stream is at the end of a section of values. This moves the stream to next tag
210      * and checks if it finds an end tag at the specified depth.
211      *
212      * @param in           XmlPullParser instance pointing to the XML stream.
213      * @param sectionDepth depth of the start tag of this section. Used to match the end tag.
214      * @return {@code true} if a end tag at the provided depth is found, {@code false} otherwise
215      * @throws XmlPullParserException if parsing errors occur.
216      */
isNextSectionEnd(XmlPullParser in, int sectionDepth)217     public static boolean isNextSectionEnd(XmlPullParser in, int sectionDepth)
218             throws XmlPullParserException, IOException {
219         return !XmlUtilHelper.nextElementWithin(in, sectionDepth);
220     }
221 
222     /**
223      * Read the current value in the XML stream using core XmlUtils and stores the retrieved
224      * value name in the string provided. This method reads the value contained in current start
225      * tag.
226      * Note: Because there could be genuine null values being read from the XML, this method raises
227      * an exception to indicate errors.
228      *
229      * @param in        XmlPullParser instance pointing to the XML stream.
230      * @param valueName An array of one string, used to return the name attribute
231      *                  of the value's tag.
232      * @return value retrieved from the XML stream.
233      * @throws XmlPullParserException if parsing errors occur.
234      */
readCurrentValue(XmlPullParser in, String[] valueName)235     public static Object readCurrentValue(XmlPullParser in, String[] valueName)
236             throws XmlPullParserException, IOException {
237         Object value = XmlUtilHelper.readValueXml(in, valueName);
238         // XmlUtils.readValue does not always move the stream to the end of the tag. So, move
239         // it to the end tag before returning from here.
240         gotoEndTag(in);
241         return value;
242     }
243 
244     /**
245      * Read the next value in the XML stream using core XmlUtils and ensure that it matches the
246      * provided name. This method moves the stream to the next start tag and reads the value
247      * contained in it.
248      * Note: Because there could be genuine null values being read from the XML, this method raises
249      * an exception to indicate errors.
250      *
251      * @param in XmlPullParser instance pointing to the XML stream.
252      * @return value retrieved from the XML stream.
253      * @throws XmlPullParserException if the value read does not match |expectedName|,
254      *                                or if parsing errors occur.
255      */
readNextValueWithName(XmlPullParser in, String expectedName)256     public static Object readNextValueWithName(XmlPullParser in, String expectedName)
257             throws XmlPullParserException, IOException {
258         String[] valueName = new String[1];
259         XmlUtilHelper.nextElement(in);
260         Object value = readCurrentValue(in, valueName);
261         if (valueName[0].equals(expectedName)) {
262             return value;
263         }
264         throw new XmlPullParserException(
265                 "Value not found. Expected: " + expectedName + ", but got: " + valueName[0]);
266     }
267 
268     /**
269      * Write the XML document start with the provided document header name.
270      *
271      * @param out        XmlSerializer instance pointing to the XML stream.
272      * @param headerName name for the start tag.
273      */
writeDocumentStart(XmlSerializer out, String headerName)274     public static void writeDocumentStart(XmlSerializer out, String headerName)
275             throws IOException {
276         out.startDocument(null, true);
277         out.startTag(null, headerName);
278     }
279 
280     /**
281      * Write the XML document end with the provided document header name.
282      *
283      * @param out        XmlSerializer instance pointing to the XML stream.
284      * @param headerName name for the end tag.
285      */
writeDocumentEnd(XmlSerializer out, String headerName)286     public static void writeDocumentEnd(XmlSerializer out, String headerName)
287             throws IOException {
288         out.endTag(null, headerName);
289         out.endDocument();
290     }
291 
292     /**
293      * Write a section start header tag with the provided section name.
294      *
295      * @param out        XmlSerializer instance pointing to the XML stream.
296      * @param headerName name for the start tag.
297      */
writeNextSectionStart(XmlSerializer out, String headerName)298     public static void writeNextSectionStart(XmlSerializer out, String headerName)
299             throws IOException {
300         out.startTag(null, headerName);
301     }
302 
303     /**
304      * Write a section end header tag with the provided section name.
305      *
306      * @param out        XmlSerializer instance pointing to the XML stream.
307      * @param headerName name for the end tag.
308      */
writeNextSectionEnd(XmlSerializer out, String headerName)309     public static void writeNextSectionEnd(XmlSerializer out, String headerName)
310             throws IOException {
311         out.endTag(null, headerName);
312     }
313 
314     /**
315      * Write the value with the provided name in the XML stream using core XmlUtils.
316      *
317      * @param out   XmlSerializer instance pointing to the XML stream.
318      * @param name  name of the value.
319      * @param value value to be written.
320      */
writeNextValue(XmlSerializer out, String name, Object value)321     public static void writeNextValue(XmlSerializer out, String name, Object value)
322             throws XmlPullParserException, IOException {
323         XmlUtilHelper.writeValueXml(value, name, out);
324     }
325 
326     /**
327      * Utility class to serialize and deserialize {@link WifiConfiguration} object to XML &
328      * vice versa.
329      * This is used by both {@link com.android.server.wifi.WifiConfigStore} &
330      * {@link com.android.server.wifi.WifiBackupRestore} modules.
331      * The |writeConfigurationToXml| has 2 versions, one for backup and one for config store.
332      * There is only 1 version of |parseXmlToConfiguration| for both backup & config store.
333      * The parse method is written so that any element added/deleted in future revisions can
334      * be easily handled.
335      */
336     public static class WifiConfigurationXmlUtil {
337         /**
338          * List of XML tags corresponding to WifiConfiguration object elements.
339          */
340         public static final String XML_TAG_SSID = "SSID";
341         public static final String XML_TAG_BSSID = "BSSID";
342         public static final String XML_TAG_CONFIG_KEY = "ConfigKey";
343         public static final String XML_TAG_PRE_SHARED_KEY = "PreSharedKey";
344         public static final String XML_TAG_WEP_KEYS = "WEPKeys";
345         public static final String XML_TAG_WEP_TX_KEY_INDEX = "WEPTxKeyIndex";
346         public static final String XML_TAG_HIDDEN_SSID = "HiddenSSID";
347         public static final String XML_TAG_REQUIRE_PMF = "RequirePMF";
348         public static final String XML_TAG_ALLOWED_KEY_MGMT = "AllowedKeyMgmt";
349         public static final String XML_TAG_ALLOWED_PROTOCOLS = "AllowedProtocols";
350         public static final String XML_TAG_ALLOWED_AUTH_ALGOS = "AllowedAuthAlgos";
351         public static final String XML_TAG_ALLOWED_GROUP_CIPHERS = "AllowedGroupCiphers";
352         public static final String XML_TAG_ALLOWED_PAIRWISE_CIPHERS = "AllowedPairwiseCiphers";
353         public static final String XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS = "AllowedGroupMgmtCiphers";
354         public static final String XML_TAG_ALLOWED_SUITE_B_CIPHERS = "AllowedSuiteBCiphers";
355         public static final String XML_TAG_SHARED = "Shared";
356         public static final String XML_TAG_STATUS = "Status";
357         public static final String XML_TAG_FQDN = "FQDN";
358         public static final String XML_TAG_PROVIDER_FRIENDLY_NAME = "ProviderFriendlyName";
359         public static final String XML_TAG_LINKED_NETWORKS_LIST = "LinkedNetworksList";
360         public static final String XML_TAG_DEFAULT_GW_MAC_ADDRESS = "DefaultGwMacAddress";
361         public static final String XML_TAG_VALIDATED_INTERNET_ACCESS = "ValidatedInternetAccess";
362         public static final String XML_TAG_NO_INTERNET_ACCESS_EXPECTED = "NoInternetAccessExpected";
363         public static final String XML_TAG_METERED_HINT = "MeteredHint";
364         public static final String XML_TAG_METERED_OVERRIDE = "MeteredOverride";
365         public static final String XML_TAG_USE_EXTERNAL_SCORES = "UseExternalScores";
366         public static final String XML_TAG_CREATOR_UID = "CreatorUid";
367         public static final String XML_TAG_CREATOR_NAME = "CreatorName";
368         public static final String XML_TAG_LAST_UPDATE_UID = "LastUpdateUid";
369         public static final String XML_TAG_LAST_UPDATE_NAME = "LastUpdateName";
370         public static final String XML_TAG_LAST_CONNECT_UID = "LastConnectUid";
371         public static final String XML_TAG_IS_LEGACY_PASSPOINT_CONFIG = "IsLegacyPasspointConfig";
372         public static final String XML_TAG_ROAMING_CONSORTIUM_OIS = "RoamingConsortiumOIs";
373         public static final String XML_TAG_RANDOMIZED_MAC_ADDRESS = "RandomizedMacAddress";
374         public static final String XML_TAG_MAC_RANDOMIZATION_SETTING = "MacRandomizationSetting";
375         public static final String XML_TAG_SEND_DHCP_HOSTNAME = "SendDhcpHostname";
376         public static final String XML_TAG_CARRIER_ID = "CarrierId";
377         public static final String XML_TAG_SUBSCRIPTION_ID = "SubscriptionId";
378         public static final String XML_TAG_IS_AUTO_JOIN = "AutoJoinEnabled";
379         public static final String XML_TAG_PRIORITY = "Priority";
380         public static final String XML_TAG_DELETION_PRIORITY = "DeletionPriority";
381         public static final String XML_TAG_NUM_REBOOTS_SINCE_LAST_USE = "NumRebootsSinceLastUse";
382 
383         public static final String XML_TAG_IS_TRUSTED = "Trusted";
384         public static final String XML_TAG_IS_OEM_PAID = "OemPaid";
385         public static final String XML_TAG_IS_OEM_PRIVATE = "OemPrivate";
386         public static final String XML_TAG_IS_CARRIER_MERGED = "CarrierMerged";
387         public static final String XML_TAG_SECURITY_PARAMS_LIST = "SecurityParamsList";
388         public static final String XML_TAG_SECURITY_PARAMS = "SecurityParams";
389         public static final String XML_TAG_SECURITY_TYPE = "SecurityType";
390         public static final String XML_TAG_IS_ENABLED = "IsEnabled";
391         public static final String XML_TAG_SAE_IS_H2E_ONLY_MODE = "SaeIsH2eOnlyMode";
392         public static final String XML_TAG_SAE_IS_PK_ONLY_MODE = "SaeIsPkOnlyMode";
393         public static final String XML_TAG_IS_ADDED_BY_AUTO_UPGRADE = "IsAddedByAutoUpgrade";
394         private static final String XML_TAG_IS_MOST_RECENTLY_CONNECTED = "IsMostRecentlyConnected";
395         private static final String XML_TAG_IS_RESTRICTED = "IsRestricted";
396         private static final String XML_TAG_SUBSCRIPTION_GROUP = "SubscriptionGroup";
397         public static final String XML_TAG_BSSID_ALLOW_LIST = "bssidAllowList";
398         public static final String XML_TAG_IS_REPEATER_ENABLED = "RepeaterEnabled";
399         public static final String XML_TAG_DPP_PRIVATE_EC_KEY = "DppPrivateEcKey";
400         public static final String XML_TAG_DPP_CONNECTOR = "DppConnector";
401         public static final String XML_TAG_DPP_CSIGN_KEY = "DppCSignKey";
402         public static final String XML_TAG_DPP_NET_ACCESS_KEY = "DppNetAccessKey";
403         public static final String XML_TAG_ENABLE_WIFI7 = "EnableWifi7";
404 
405         /**
406          * Write Wep Keys to the XML stream.
407          * WepKeys array is initialized in WifiConfiguration constructor and all the elements
408          * are set to null. User may choose to set any one of the key elements in WifiConfiguration.
409          * XmlUtils serialization doesn't handle this array of nulls well .
410          * So, write empty strings if the keys are not initialized and null if all
411          * the elements are empty.
412          */
writeWepKeysToXml(XmlSerializer out, String[] wepKeys, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)413         private static void writeWepKeysToXml(XmlSerializer out, String[] wepKeys,
414                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
415                 throws XmlPullParserException, IOException {
416             final int len = wepKeys == null ? 0 : wepKeys.length;
417             String[] wepKeysToWrite = new String[len];
418             boolean hasWepKey = false;
419             for (int i = 0; i < len; i++) {
420                 if (wepKeys[i] == null) {
421                     wepKeysToWrite[i] = new String();
422                 } else {
423                     wepKeysToWrite[i] = wepKeys[i];
424                     hasWepKey = true;
425                 }
426             }
427             if (!hasWepKey) {
428                 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, null);
429                 return;
430             }
431             if (encryptionUtil == null) {
432                 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, wepKeysToWrite);
433                 return;
434             }
435             EncryptedData[] encryptedDataArray = new EncryptedData[len];
436             for (int i = 0; i < len; i++) {
437                 if (wepKeys[i] == null) {
438                     encryptedDataArray[i] = new EncryptedData(new byte[0], new byte[0]);
439                 } else {
440                     encryptedDataArray[i] = encryptionUtil.encrypt(wepKeys[i].getBytes());
441                     if (encryptedDataArray[i] == null) {
442                         // We silently fail encryption failures!
443                         Log.wtf(TAG, "Encryption of WEP keys failed");
444                         // If any key encryption fails, we just fall back with unencrypted keys.
445                         XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, wepKeysToWrite);
446                         return;
447                     }
448                 }
449             }
450             XmlUtil.writeNextSectionStart(out, XML_TAG_WEP_KEYS);
451             for (int i = 0; i < len; i++) {
452                 XmlUtil.EncryptedDataXmlUtil.writeToXml(out, encryptedDataArray[i]);
453             }
454             XmlUtil.writeNextSectionEnd(out, XML_TAG_WEP_KEYS);
455         }
456 
457         /**
458          * Write preshared key to the XML stream.
459          *
460          * If encryptionUtil is null or if encryption fails for some reason, the pre-shared
461          * key is stored in plaintext, else the encrypted psk is stored.
462          */
writePreSharedKeyToXml( XmlSerializer out, WifiConfiguration wifiConfig, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)463         private static void writePreSharedKeyToXml(
464                 XmlSerializer out, WifiConfiguration wifiConfig,
465                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
466                 throws XmlPullParserException, IOException {
467             EncryptedData encryptedData = null;
468             if (encryptionUtil != null && wifiConfig.preSharedKey != null) {
469                 if (wifiConfig.hasEncryptedPreSharedKey() && !wifiConfig.hasPreSharedKeyChanged()) {
470                     encryptedData = new EncryptedData(wifiConfig.getEncryptedPreSharedKey(),
471                             wifiConfig.getEncryptedPreSharedKeyIv());
472                 } else {
473                     encryptedData = encryptionUtil.encrypt(wifiConfig.preSharedKey.getBytes());
474                     if (encryptedData == null) {
475                         // We silently fail encryption failures!
476                         Log.wtf(TAG, "Encryption of preSharedKey failed");
477                     }
478                 }
479             }
480             if (encryptedData != null) {
481                 writeNextSectionStart(out, XML_TAG_PRE_SHARED_KEY);
482                 EncryptedDataXmlUtil.writeToXml(out, encryptedData);
483                 wifiConfig.setEncryptedPreSharedKey(encryptedData.getEncryptedData(),
484                         encryptedData.getIv());
485                 wifiConfig.setHasPreSharedKeyChanged(false);
486                 writeNextSectionEnd(out, XML_TAG_PRE_SHARED_KEY);
487             } else {
488                 writeNextValue(out, XML_TAG_PRE_SHARED_KEY, wifiConfig.preSharedKey);
489             }
490         }
491 
writeSecurityParamsListToXml( XmlSerializer out, WifiConfiguration configuration)492         private static void writeSecurityParamsListToXml(
493                 XmlSerializer out, WifiConfiguration configuration)
494                 throws XmlPullParserException, IOException {
495             XmlUtil.writeNextSectionStart(out, XML_TAG_SECURITY_PARAMS_LIST);
496             for (SecurityParams params: configuration.getSecurityParamsList()) {
497                 XmlUtil.writeNextSectionStart(out, XML_TAG_SECURITY_PARAMS);
498                 XmlUtil.writeNextValue(
499                         out, XML_TAG_SECURITY_TYPE,
500                         params.getSecurityType());
501                 XmlUtil.writeNextValue(
502                         out, XML_TAG_IS_ENABLED,
503                         params.isEnabled());
504                 XmlUtil.writeNextValue(
505                         out, XML_TAG_SAE_IS_H2E_ONLY_MODE,
506                         params.isSaeH2eOnlyMode());
507                 XmlUtil.writeNextValue(
508                         out, XML_TAG_SAE_IS_PK_ONLY_MODE,
509                         params.isSaePkOnlyMode());
510                 XmlUtil.writeNextValue(
511                         out, XML_TAG_IS_ADDED_BY_AUTO_UPGRADE,
512                         params.isAddedByAutoUpgrade());
513                 XmlUtil.writeNextValue(
514                         out, XML_TAG_ALLOWED_SUITE_B_CIPHERS,
515                         params.getAllowedSuiteBCiphers().toByteArray());
516                 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECURITY_PARAMS);
517             }
518 
519             XmlUtil.writeNextSectionEnd(out, XML_TAG_SECURITY_PARAMS_LIST);
520         }
521 
writeEncryptedBytesToXml( XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, String tag, byte[] data)522         private static void writeEncryptedBytesToXml(
523                 XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil,
524                 String tag, byte[] data)
525                 throws XmlPullParserException, IOException {
526             EncryptedData encryptedData = null;
527             if (encryptionUtil != null) {
528                 encryptedData = encryptionUtil.encrypt(data);
529                 if (encryptedData == null && data != null && data.length != 0) {
530                     // We silently fail encryption failures!
531                     Log.wtf(TAG, "Encryption of " + tag + " failed");
532                 }
533             }
534             if (encryptedData != null) {
535                 XmlUtil.writeNextSectionStart(out, tag);
536                 EncryptedDataXmlUtil.writeToXml(out, encryptedData);
537                 XmlUtil.writeNextSectionEnd(out, tag);
538             } else {
539                 XmlUtil.writeNextValue(out, tag, data);
540             }
541         }
542 
543         /**
544          * Write dpp configuration and connection keys to the XML stream.
545          *
546          * If encryptionUtil is null or if encryption fails for some reason, the dpp
547          * keys are stored in plaintext, else the encrypted keys are stored.
548          */
writeDppConfigurationToXml( XmlSerializer out, WifiConfiguration configuration, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)549         private static void writeDppConfigurationToXml(
550                 XmlSerializer out, WifiConfiguration configuration,
551                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
552                 throws XmlPullParserException, IOException {
553             writeEncryptedBytesToXml(out, encryptionUtil, XML_TAG_DPP_PRIVATE_EC_KEY,
554                     configuration.getDppPrivateEcKey());
555             writeEncryptedBytesToXml(out, encryptionUtil, XML_TAG_DPP_CONNECTOR,
556                     configuration.getDppConnector());
557             writeEncryptedBytesToXml(out, encryptionUtil, XML_TAG_DPP_CSIGN_KEY,
558                     configuration.getDppCSignKey());
559             writeEncryptedBytesToXml(out, encryptionUtil, XML_TAG_DPP_NET_ACCESS_KEY,
560                     configuration.getDppNetAccessKey());
561         }
562 
563         /**
564          * Write the Configuration data elements that are common for backup & config store to the
565          * XML stream.
566          *
567          * @param out XmlSerializer instance pointing to the XML stream.
568          * @param configuration WifiConfiguration object to be serialized.
569          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. Backup/restore stores
570          *                       keys unencrypted.
571          */
writeCommonElementsToXml( XmlSerializer out, WifiConfiguration configuration, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)572         public static void writeCommonElementsToXml(
573                 XmlSerializer out, WifiConfiguration configuration,
574                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
575                 throws XmlPullParserException, IOException {
576             XmlUtil.writeNextValue(out, XML_TAG_CONFIG_KEY, configuration.getKey());
577             XmlUtil.writeNextValue(out, XML_TAG_SSID, configuration.SSID);
578             writePreSharedKeyToXml(out, configuration, encryptionUtil);
579             writeWepKeysToXml(out, configuration.wepKeys, encryptionUtil);
580             XmlUtil.writeNextValue(out, XML_TAG_WEP_TX_KEY_INDEX, configuration.wepTxKeyIndex);
581             XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, configuration.hiddenSSID);
582             XmlUtil.writeNextValue(out, XML_TAG_REQUIRE_PMF, configuration.requirePmf);
583             XmlUtil.writeNextValue(
584                     out, XML_TAG_ALLOWED_KEY_MGMT,
585                     configuration.allowedKeyManagement.toByteArray());
586             XmlUtil.writeNextValue(
587                     out, XML_TAG_ALLOWED_PROTOCOLS,
588                     configuration.allowedProtocols.toByteArray());
589             XmlUtil.writeNextValue(
590                     out, XML_TAG_ALLOWED_AUTH_ALGOS,
591                     configuration.allowedAuthAlgorithms.toByteArray());
592             XmlUtil.writeNextValue(
593                     out, XML_TAG_ALLOWED_GROUP_CIPHERS,
594                     configuration.allowedGroupCiphers.toByteArray());
595             XmlUtil.writeNextValue(
596                     out, XML_TAG_ALLOWED_PAIRWISE_CIPHERS,
597                     configuration.allowedPairwiseCiphers.toByteArray());
598             XmlUtil.writeNextValue(
599                     out, XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS,
600                     configuration.allowedGroupManagementCiphers.toByteArray());
601             XmlUtil.writeNextValue(
602                     out, XML_TAG_ALLOWED_SUITE_B_CIPHERS,
603                     configuration.allowedSuiteBCiphers.toByteArray());
604             XmlUtil.writeNextValue(out, XML_TAG_SHARED, configuration.shared);
605             XmlUtil.writeNextValue(out, XML_TAG_IS_AUTO_JOIN, configuration.allowAutojoin);
606             XmlUtil.writeNextValue(out, XML_TAG_PRIORITY, configuration.priority);
607             XmlUtil.writeNextValue(
608                     out, XML_TAG_DELETION_PRIORITY,
609                     configuration.getDeletionPriority());
610             XmlUtil.writeNextValue(
611                     out, XML_TAG_NUM_REBOOTS_SINCE_LAST_USE,
612                     configuration.numRebootsSinceLastUse);
613             XmlUtil.writeNextValue(out, XML_TAG_IS_REPEATER_ENABLED,
614                     configuration.isRepeaterEnabled());
615             XmlUtil.writeNextValue(out, XML_TAG_ENABLE_WIFI7, configuration.isWifi7Enabled());
616             writeSecurityParamsListToXml(out, configuration);
617             XmlUtil.writeNextValue(out, XML_TAG_SEND_DHCP_HOSTNAME,
618                     configuration.isSendDhcpHostnameEnabled());
619         }
620 
621         /**
622          * Write the Configuration data elements for backup from the provided Configuration to the
623          * XML stream.
624          * Note: This is a subset of the elements serialized for config store.
625          *
626          * @param out           XmlSerializer instance pointing to the XML stream.
627          * @param configuration WifiConfiguration object to be serialized.
628          */
writeToXmlForBackup(XmlSerializer out, WifiConfiguration configuration)629         public static void writeToXmlForBackup(XmlSerializer out, WifiConfiguration configuration)
630                 throws XmlPullParserException, IOException {
631             writeCommonElementsToXml(out, configuration, null);
632             XmlUtil.writeNextValue(out, XML_TAG_METERED_OVERRIDE, configuration.meteredOverride);
633         }
634 
635         /**
636          * Write the Configuration data elements for config store from the provided Configuration
637          * to the XML stream.
638          *
639          * @param out XmlSerializer instance pointing to the XML stream.
640          * @param configuration WifiConfiguration object to be serialized.
641          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}.
642          */
writeToXmlForConfigStore( XmlSerializer out, WifiConfiguration configuration, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)643         public static void writeToXmlForConfigStore(
644                 XmlSerializer out, WifiConfiguration configuration,
645                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
646                 throws XmlPullParserException, IOException {
647             writeCommonElementsToXml(out, configuration, encryptionUtil);
648             XmlUtil.writeNextValue(out, XML_TAG_IS_TRUSTED, configuration.trusted);
649             XmlUtil.writeNextValue(out, XML_TAG_IS_RESTRICTED, configuration.restricted);
650             XmlUtil.writeNextValue(out, XML_TAG_IS_OEM_PAID, configuration.oemPaid);
651             XmlUtil.writeNextValue(out, XML_TAG_IS_OEM_PRIVATE, configuration.oemPrivate);
652             XmlUtil.writeNextValue(out, XML_TAG_IS_CARRIER_MERGED,
653                     configuration.carrierMerged);
654             XmlUtil.writeNextValue(out, XML_TAG_BSSID, configuration.BSSID);
655             XmlUtil.writeNextValue(out, XML_TAG_STATUS, configuration.status);
656             XmlUtil.writeNextValue(out, XML_TAG_FQDN, configuration.FQDN);
657             XmlUtil.writeNextValue(
658                     out, XML_TAG_PROVIDER_FRIENDLY_NAME, configuration.providerFriendlyName);
659             XmlUtil.writeNextValue(
660                     out, XML_TAG_LINKED_NETWORKS_LIST, configuration.linkedConfigurations);
661             XmlUtil.writeNextValue(
662                     out, XML_TAG_DEFAULT_GW_MAC_ADDRESS, configuration.defaultGwMacAddress);
663             XmlUtil.writeNextValue(
664                     out, XML_TAG_VALIDATED_INTERNET_ACCESS, configuration.validatedInternetAccess);
665             XmlUtil.writeNextValue(
666                     out, XML_TAG_NO_INTERNET_ACCESS_EXPECTED,
667                     configuration.noInternetAccessExpected);
668             XmlUtil.writeNextValue(out, XML_TAG_METERED_HINT, configuration.meteredHint);
669             XmlUtil.writeNextValue(out, XML_TAG_METERED_OVERRIDE, configuration.meteredOverride);
670             XmlUtil.writeNextValue(
671                     out, XML_TAG_USE_EXTERNAL_SCORES, configuration.useExternalScores);
672             XmlUtil.writeNextValue(out, XML_TAG_CREATOR_UID, configuration.creatorUid);
673             XmlUtil.writeNextValue(out, XML_TAG_CREATOR_NAME, configuration.creatorName);
674             XmlUtil.writeNextValue(out, XML_TAG_LAST_UPDATE_UID, configuration.lastUpdateUid);
675             XmlUtil.writeNextValue(out, XML_TAG_LAST_UPDATE_NAME, configuration.lastUpdateName);
676             XmlUtil.writeNextValue(out, XML_TAG_LAST_CONNECT_UID, configuration.lastConnectUid);
677             XmlUtil.writeNextValue(
678                     out, XML_TAG_IS_LEGACY_PASSPOINT_CONFIG,
679                     configuration.isLegacyPasspointConfig);
680             XmlUtil.writeNextValue(
681                     out, XML_TAG_ROAMING_CONSORTIUM_OIS, configuration.roamingConsortiumIds);
682             XmlUtil.writeNextValue(out, XML_TAG_RANDOMIZED_MAC_ADDRESS,
683                     configuration.getRandomizedMacAddress().toString());
684             XmlUtil.writeNextValue(out, XML_TAG_MAC_RANDOMIZATION_SETTING,
685                     configuration.macRandomizationSetting);
686             XmlUtil.writeNextValue(out, XML_TAG_CARRIER_ID, configuration.carrierId);
687             XmlUtil.writeNextValue(out, XML_TAG_IS_MOST_RECENTLY_CONNECTED,
688                     configuration.isMostRecentlyConnected);
689             XmlUtil.writeNextValue(out, XML_TAG_SUBSCRIPTION_ID, configuration.subscriptionId);
690             if (configuration.getSubscriptionGroup() != null) {
691                 XmlUtil.writeNextValue(out, XML_TAG_SUBSCRIPTION_GROUP,
692                         configuration.getSubscriptionGroup().toString());
693             }
694             if (configuration.getBssidAllowlistInternal() != null) {
695                 XmlUtil.writeNextValue(out, XML_TAG_BSSID_ALLOW_LIST,
696                         covertMacAddressListToStringList(configuration
697                                 .getBssidAllowlistInternal()));
698             }
699             writeDppConfigurationToXml(out, configuration, encryptionUtil);
700             if (SdkLevel.isAtLeastV()) {
701                 writeVendorDataListToXml(out, configuration.getVendorData());
702             }
703         }
704 
covertMacAddressListToStringList(List<MacAddress> macList)705         private static List<String> covertMacAddressListToStringList(List<MacAddress> macList) {
706             List<String> bssidList = new ArrayList<>();
707             for (MacAddress address : macList) {
708                 bssidList.add(address.toString());
709             }
710             return bssidList;
711         }
712 
covertStringListToMacAddressList(List<String> stringList)713         private static List<MacAddress> covertStringListToMacAddressList(List<String> stringList) {
714             List<MacAddress> macAddressList = new ArrayList<>();
715             for (String address : stringList) {
716                 try {
717                     macAddressList.add(MacAddress.fromString(address));
718                 } catch (Exception e) {
719                     Log.e(TAG, "Invalid BSSID String: " + address);
720                 }
721             }
722             return macAddressList;
723         }
724 
725         /**
726          * Populate wepKeys array elements only if they were non-empty in the backup data.
727          *
728          * @throws XmlPullParserException if parsing errors occur.
729          */
populateWepKeysFromXmlValue(Object value, String[] wepKeys)730         private static void populateWepKeysFromXmlValue(Object value, String[] wepKeys)
731                 throws XmlPullParserException, IOException {
732             String[] wepKeysInData = (String[]) value;
733             if (wepKeysInData == null) {
734                 return;
735             }
736             if (wepKeysInData.length != wepKeys.length) {
737                 throw new XmlPullParserException(
738                         "Invalid Wep Keys length: " + wepKeysInData.length);
739             }
740             for (int i = 0; i < wepKeys.length; i++) {
741                 if (wepKeysInData[i].isEmpty()) {
742                     wepKeys[i] = null;
743                 } else {
744                     wepKeys[i] = wepKeysInData[i];
745                 }
746             }
747         }
748 
populateWepKeysFromXmlValue(XmlPullParser in, int outerTagDepth, @NonNull WifiConfigStoreEncryptionUtil encryptionUtil)749         private static String[] populateWepKeysFromXmlValue(XmlPullParser in,
750                 int outerTagDepth, @NonNull WifiConfigStoreEncryptionUtil encryptionUtil)
751                 throws XmlPullParserException, IOException {
752             List<String> wepKeyList = new ArrayList<>();
753             final List<EncryptedData> encryptedDataList =
754                     XmlUtil.EncryptedDataXmlUtil.parseListFromXml(in, outerTagDepth);
755             EncryptedData emptyData = new EncryptedData(new byte[0], new byte[0]);
756             for (int i = 0; i < encryptedDataList.size(); i++) {
757                 if (encryptedDataList.get(i).equals(emptyData)) {
758                     wepKeyList.add(null);
759                     continue;
760                 }
761                 byte[] passphraseBytes = encryptionUtil.decrypt(encryptedDataList.get(i));
762                 if (passphraseBytes == null) {
763                     Log.wtf(TAG, "Decryption of passphraseBytes failed");
764                 } else {
765                     wepKeyList.add(new String(passphraseBytes, StandardCharsets.UTF_8));
766                 }
767             }
768             return wepKeyList.size() > 0 ? wepKeyList.toArray(
769                     new String[wepKeyList.size()]) : null;
770         }
771 
parseSecurityParamsFromXml( XmlPullParser in, int outerTagDepth)772         private static SecurityParams parseSecurityParamsFromXml(
773                 XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException {
774             SecurityParams params = null;
775             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
776                 String[] valueName = new String[1];
777                 Object value = XmlUtil.readCurrentValue(in, valueName);
778                 String tagName = valueName[0];
779                 if (tagName == null) {
780                     throw new XmlPullParserException("Missing value name");
781                 }
782                 switch (tagName) {
783                     case WifiConfigurationXmlUtil.XML_TAG_SECURITY_TYPE:
784                         params = SecurityParams.createSecurityParamsBySecurityType((int) value);
785                         break;
786                     case WifiConfigurationXmlUtil.XML_TAG_IS_ENABLED:
787                         params.setEnabled((boolean) value);
788                         break;
789                     case WifiConfigurationXmlUtil.XML_TAG_SAE_IS_H2E_ONLY_MODE:
790                         if (null == params) {
791                             throw new XmlPullParserException("Missing security type.");
792                         }
793                         params.enableSaeH2eOnlyMode((boolean) value);
794                         break;
795                     case WifiConfigurationXmlUtil.XML_TAG_SAE_IS_PK_ONLY_MODE:
796                         if (null == params) {
797                             throw new XmlPullParserException("Missing security type.");
798                         }
799                         params.enableSaePkOnlyMode((boolean) value);
800                         break;
801                     case WifiConfigurationXmlUtil.XML_TAG_IS_ADDED_BY_AUTO_UPGRADE:
802                         if (null == params) {
803                             throw new XmlPullParserException("Missing security type.");
804                         }
805                         params.setIsAddedByAutoUpgrade((boolean) value);
806                         break;
807                     case WifiConfigurationXmlUtil.XML_TAG_ALLOWED_SUITE_B_CIPHERS:
808                         if (null == params) {
809                             throw new XmlPullParserException("Missing security type.");
810                         }
811                         byte[] suiteBCiphers = (byte[]) value;
812                         BitSet suiteBCiphersBitSet = BitSet.valueOf(suiteBCiphers);
813                         params.enableSuiteBCiphers(
814                                 suiteBCiphersBitSet.get(WifiConfiguration.SuiteBCipher.ECDHE_ECDSA),
815                                 suiteBCiphersBitSet.get(WifiConfiguration.SuiteBCipher.ECDHE_RSA));
816                         break;
817                 }
818             }
819             return params;
820         }
821 
readEncrytepdBytesFromXml( @ullable WifiConfigStoreEncryptionUtil encryptionUtil, XmlPullParser in, int outerTagDepth)822         private static byte[] readEncrytepdBytesFromXml(
823                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil,
824                 XmlPullParser in, int outerTagDepth)
825                 throws XmlPullParserException, IOException {
826             if (encryptionUtil == null) {
827                 throw new XmlPullParserException(
828                         "Encrypted preSharedKey section not expected");
829             }
830             EncryptedData encryptedData =
831                     EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1);
832             return encryptionUtil.decrypt(encryptedData);
833         }
834 
parseSecurityParamsListFromXml( XmlPullParser in, int outerTagDepth, WifiConfiguration configuration)835         private static void parseSecurityParamsListFromXml(
836                 XmlPullParser in, int outerTagDepth,
837                 WifiConfiguration configuration)
838                 throws XmlPullParserException, IOException {
839             List<SecurityParams> paramsList = new ArrayList<>();
840             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
841                 switch (in.getName()) {
842                     case WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS:
843                         SecurityParams params = parseSecurityParamsFromXml(in, outerTagDepth + 1);
844                         if (params != null) {
845                             paramsList.add(params);
846                         }
847                         break;
848                 }
849             }
850             if (!paramsList.isEmpty()) {
851                 configuration.setSecurityParams(paramsList);
852             }
853         }
854 
855         /**
856          * Parses the configuration data elements from the provided XML stream to a
857          * WifiConfiguration object.
858          * Note: This is used for parsing both backup data and config store data. Looping through
859          * the tags make it easy to add or remove elements in the future versions if needed.
860          *
861          * @param in XmlPullParser instance pointing to the XML stream.
862          * @param outerTagDepth depth of the outer tag in the XML document.
863          * @param shouldExpectEncryptedCredentials Whether to expect encrypted credentials or not.
864          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}.
865          * @param fromSuggestion Is this WifiConfiguration created from a WifiNetworkSuggestion.
866          * @return Pair<Config key, WifiConfiguration object> if parsing is successful,
867          * null otherwise.
868          */
parseFromXml( XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, boolean fromSuggestion)869         public static Pair<String, WifiConfiguration> parseFromXml(
870                 XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials,
871                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, boolean fromSuggestion)
872                 throws XmlPullParserException, IOException {
873             WifiConfiguration configuration = new WifiConfiguration();
874             String configKeyInData = null;
875             boolean macRandomizationSettingExists = false;
876             boolean sendDhcpHostnameExists = false;
877             byte[] dppConnector = null;
878             byte[] dppCSign = null;
879             byte[] dppNetAccessKey = null;
880 
881             // Loop through and parse out all the elements from the stream within this section.
882             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
883                 if (in.getAttributeValue(null, "name") != null) {
884                     // Value elements.
885                     String[] valueName = new String[1];
886                     Object value = XmlUtil.readCurrentValue(in, valueName);
887                     if (valueName[0] == null) {
888                         throw new XmlPullParserException("Missing value name");
889                     }
890                     switch (valueName[0]) {
891                         case XML_TAG_CONFIG_KEY:
892                             configKeyInData = (String) value;
893                             break;
894                         case XML_TAG_SSID:
895                             configuration.SSID = (String) value;
896                             break;
897                         case XML_TAG_BSSID:
898                             configuration.BSSID = (String) value;
899                             break;
900                         case XML_TAG_PRE_SHARED_KEY:
901                             configuration.preSharedKey = (String) value;
902                             break;
903                         case XML_TAG_WEP_KEYS:
904                             populateWepKeysFromXmlValue(value, configuration.wepKeys);
905                             break;
906                         case XML_TAG_WEP_TX_KEY_INDEX:
907                             configuration.wepTxKeyIndex = (int) value;
908                             break;
909                         case XML_TAG_HIDDEN_SSID:
910                             configuration.hiddenSSID = (boolean) value;
911                             break;
912                         case XML_TAG_REQUIRE_PMF:
913                             configuration.requirePmf = (boolean) value;
914                             break;
915                         case XML_TAG_ALLOWED_KEY_MGMT:
916                             byte[] allowedKeyMgmt = (byte[]) value;
917                             configuration.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt);
918                             break;
919                         case XML_TAG_ALLOWED_PROTOCOLS:
920                             byte[] allowedProtocols = (byte[]) value;
921                             configuration.allowedProtocols = BitSet.valueOf(allowedProtocols);
922                             break;
923                         case XML_TAG_ALLOWED_AUTH_ALGOS:
924                             byte[] allowedAuthAlgorithms = (byte[]) value;
925                             configuration.allowedAuthAlgorithms = BitSet.valueOf(
926                                     allowedAuthAlgorithms);
927                             break;
928                         case XML_TAG_ALLOWED_GROUP_CIPHERS:
929                             byte[] allowedGroupCiphers = (byte[]) value;
930                             configuration.allowedGroupCiphers = BitSet.valueOf(allowedGroupCiphers);
931                             break;
932                         case XML_TAG_ALLOWED_PAIRWISE_CIPHERS:
933                             byte[] allowedPairwiseCiphers = (byte[]) value;
934                             configuration.allowedPairwiseCiphers =
935                                     BitSet.valueOf(allowedPairwiseCiphers);
936                             break;
937                         case XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS:
938                             byte[] allowedGroupMgmtCiphers = (byte[]) value;
939                             configuration.allowedGroupManagementCiphers =
940                                     BitSet.valueOf(allowedGroupMgmtCiphers);
941                             break;
942                         case XML_TAG_ALLOWED_SUITE_B_CIPHERS:
943                             byte[] allowedSuiteBCiphers = (byte[]) value;
944                             configuration.allowedSuiteBCiphers =
945                                     BitSet.valueOf(allowedSuiteBCiphers);
946                             break;
947                         case XML_TAG_SHARED:
948                             configuration.shared = (boolean) value;
949                             break;
950                         case XML_TAG_STATUS:
951                             int status = (int) value;
952                             // Any network which was CURRENT before reboot needs
953                             // to be restored to ENABLED.
954                             if (status == WifiConfiguration.Status.CURRENT) {
955                                 status = WifiConfiguration.Status.ENABLED;
956                             }
957                             configuration.status = status;
958                             break;
959                         case XML_TAG_FQDN:
960                             configuration.FQDN = (String) value;
961                             break;
962                         case XML_TAG_PROVIDER_FRIENDLY_NAME:
963                             configuration.providerFriendlyName = (String) value;
964                             break;
965                         case XML_TAG_LINKED_NETWORKS_LIST:
966                             configuration.linkedConfigurations = (HashMap<String, Integer>) value;
967                             break;
968                         case XML_TAG_DEFAULT_GW_MAC_ADDRESS:
969                             configuration.defaultGwMacAddress = (String) value;
970                             break;
971                         case XML_TAG_VALIDATED_INTERNET_ACCESS:
972                             configuration.validatedInternetAccess = (boolean) value;
973                             break;
974                         case XML_TAG_NO_INTERNET_ACCESS_EXPECTED:
975                             configuration.noInternetAccessExpected = (boolean) value;
976                             break;
977                         case XML_TAG_METERED_HINT:
978                             configuration.meteredHint = (boolean) value;
979                             break;
980                         case XML_TAG_METERED_OVERRIDE:
981                             configuration.meteredOverride = (int) value;
982                             break;
983                         case XML_TAG_USE_EXTERNAL_SCORES:
984                             configuration.useExternalScores = (boolean) value;
985                             break;
986                         case XML_TAG_CREATOR_UID:
987                             configuration.creatorUid = (int) value;
988                             break;
989                         case XML_TAG_CREATOR_NAME:
990                             configuration.creatorName = (String) value;
991                             break;
992                         case XML_TAG_LAST_UPDATE_UID:
993                             configuration.lastUpdateUid = (int) value;
994                             break;
995                         case XML_TAG_LAST_UPDATE_NAME:
996                             configuration.lastUpdateName = (String) value;
997                             break;
998                         case XML_TAG_LAST_CONNECT_UID:
999                             configuration.lastConnectUid = (int) value;
1000                             break;
1001                         case XML_TAG_IS_LEGACY_PASSPOINT_CONFIG:
1002                             configuration.isLegacyPasspointConfig = (boolean) value;
1003                             break;
1004                         case XML_TAG_ROAMING_CONSORTIUM_OIS:
1005                             configuration.roamingConsortiumIds = (long[]) value;
1006                             break;
1007                         case XML_TAG_RANDOMIZED_MAC_ADDRESS:
1008                             configuration.setRandomizedMacAddress(
1009                                     MacAddress.fromString((String) value));
1010                             break;
1011                         case XML_TAG_MAC_RANDOMIZATION_SETTING:
1012                             configuration.macRandomizationSetting = (int) value;
1013                             macRandomizationSettingExists = true;
1014                             break;
1015                         case XML_TAG_SEND_DHCP_HOSTNAME:
1016                             configuration.setSendDhcpHostnameEnabled((boolean) value);
1017                             sendDhcpHostnameExists = true;
1018                             break;
1019                         case XML_TAG_CARRIER_ID:
1020                             configuration.carrierId = (int) value;
1021                             break;
1022                         case XML_TAG_SUBSCRIPTION_ID:
1023                             configuration.subscriptionId = (int) value;
1024                             break;
1025                         case XML_TAG_IS_AUTO_JOIN:
1026                             configuration.allowAutojoin = (boolean) value;
1027                             break;
1028                         case XML_TAG_PRIORITY:
1029                             configuration.priority = (int) value;
1030                             break;
1031                         case XML_TAG_DELETION_PRIORITY:
1032                             configuration.setDeletionPriority((int) value);
1033                             break;
1034                         case XML_TAG_NUM_REBOOTS_SINCE_LAST_USE:
1035                             configuration.numRebootsSinceLastUse = (int) value;
1036                             break;
1037                         case XML_TAG_IS_TRUSTED:
1038                             configuration.trusted = (boolean) value;
1039                             break;
1040                         case XML_TAG_IS_OEM_PAID:
1041                             configuration.oemPaid = (boolean) value;
1042                             break;
1043                         case XML_TAG_IS_OEM_PRIVATE:
1044                             configuration.oemPrivate = (boolean) value;
1045                             break;
1046                         case XML_TAG_IS_MOST_RECENTLY_CONNECTED:
1047                             configuration.isMostRecentlyConnected = (boolean) value;
1048                             break;
1049                         case XML_TAG_IS_CARRIER_MERGED:
1050                             configuration.carrierMerged = (boolean) value;
1051                             break;
1052                         case XML_TAG_IS_RESTRICTED:
1053                             configuration.restricted = (boolean) value;
1054                             break;
1055                         case XML_TAG_SUBSCRIPTION_GROUP:
1056                             configuration.setSubscriptionGroup(
1057                                     ParcelUuid.fromString((String) value));
1058                             break;
1059                         case XML_TAG_BSSID_ALLOW_LIST:
1060                             configuration.setBssidAllowlist(
1061                                     covertStringListToMacAddressList((List<String>) value));
1062                             break;
1063                         case XML_TAG_IS_REPEATER_ENABLED:
1064                             configuration.setRepeaterEnabled((boolean) value);
1065                             break;
1066                         case XML_TAG_DPP_PRIVATE_EC_KEY:
1067                             configuration.setDppConfigurator((byte[]) value);
1068                             break;
1069                         case XML_TAG_DPP_CONNECTOR:
1070                             dppConnector = (byte[]) value;
1071                             break;
1072                         case XML_TAG_DPP_CSIGN_KEY:
1073                             dppCSign = (byte[]) value;
1074                             break;
1075                         case XML_TAG_DPP_NET_ACCESS_KEY:
1076                             dppNetAccessKey = (byte[]) value;
1077                             break;
1078                         case XML_TAG_ENABLE_WIFI7:
1079                             configuration.setWifi7Enabled((boolean) value);
1080                             break;
1081                         default:
1082                             Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]);
1083                             break;
1084                     }
1085                 } else {
1086                     String tagName = in.getName();
1087                     if (tagName == null) {
1088                         throw new XmlPullParserException("Unexpected null tag found");
1089                     }
1090                     switch (tagName) {
1091                         case XML_TAG_PRE_SHARED_KEY:
1092                             if (!shouldExpectEncryptedCredentials || encryptionUtil == null) {
1093                                 throw new XmlPullParserException(
1094                                         "Encrypted preSharedKey section not expected");
1095                             }
1096                             EncryptedData encryptedData =
1097                                     EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1);
1098                             byte[] preSharedKeyBytes = encryptionUtil.decrypt(encryptedData);
1099                             if (preSharedKeyBytes == null) {
1100                                 Log.wtf(TAG, "Decryption of preSharedKey failed");
1101                             } else {
1102                                 configuration.preSharedKey = new String(preSharedKeyBytes);
1103                                 configuration.setEncryptedPreSharedKey(
1104                                         encryptedData.getEncryptedData(),
1105                                         encryptedData.getIv());
1106                             }
1107                             break;
1108                         case XML_TAG_WEP_KEYS:
1109                             if (!shouldExpectEncryptedCredentials || encryptionUtil == null) {
1110                                 throw new XmlPullParserException(
1111                                         "Encrypted wepKeys section not expected");
1112                             }
1113                             configuration.wepKeys = populateWepKeysFromXmlValue(in,
1114                                     outerTagDepth + 1, encryptionUtil);
1115                             break;
1116                         case XML_TAG_SECURITY_PARAMS_LIST:
1117                             parseSecurityParamsListFromXml(in, outerTagDepth + 1, configuration);
1118                             break;
1119                         case XML_TAG_DPP_PRIVATE_EC_KEY:
1120                             configuration.setDppConfigurator(readEncrytepdBytesFromXml(
1121                                     encryptionUtil, in, outerTagDepth));
1122                             break;
1123                         case XML_TAG_DPP_CONNECTOR:
1124                             dppConnector = readEncrytepdBytesFromXml(encryptionUtil, in,
1125                                     outerTagDepth);
1126                             break;
1127                         case XML_TAG_DPP_CSIGN_KEY:
1128                             dppCSign = readEncrytepdBytesFromXml(encryptionUtil, in,
1129                                     outerTagDepth);
1130                             break;
1131                         case XML_TAG_DPP_NET_ACCESS_KEY:
1132                             dppNetAccessKey = readEncrytepdBytesFromXml(encryptionUtil, in,
1133                                     outerTagDepth);
1134                             break;
1135                         case XML_TAG_VENDOR_DATA_LIST:
1136                             if (SdkLevel.isAtLeastV()) {
1137                                 configuration.setVendorData(
1138                                         parseVendorDataListFromXml(in, outerTagDepth + 1));
1139                             }
1140                             break;
1141                         default:
1142                             Log.w(TAG, "Ignoring unknown tag found: " + tagName);
1143                             break;
1144                     }
1145                 }
1146             }
1147             if (!macRandomizationSettingExists) {
1148                 configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE;
1149             }
1150             if (configuration.macRandomizationSetting
1151                     == WifiConfiguration.RANDOMIZATION_PERSISTENT && !fromSuggestion) {
1152                 configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO;
1153             }
1154             if (!sendDhcpHostnameExists) {
1155                 // Update legacy configs to send the DHCP hostname for secure networks only.
1156                 configuration.setSendDhcpHostnameEnabled(
1157                         !configuration.isSecurityType(WifiConfiguration.SECURITY_TYPE_OPEN)
1158                         && !configuration.isSecurityType(WifiConfiguration.SECURITY_TYPE_OWE));
1159             }
1160             configuration.convertLegacyFieldsToSecurityParamsIfNeeded();
1161             configuration.setDppConnectionKeys(dppConnector, dppCSign, dppNetAccessKey);
1162             return Pair.create(configKeyInData, configuration);
1163         }
1164     }
1165 
1166     /**
1167      * Utility class to serialize and deseriaize {@link IpConfiguration} object to XML & vice versa.
1168      * This is used by both {@link com.android.server.wifi.WifiConfigStore} &
1169      * {@link com.android.server.wifi.WifiBackupRestore} modules.
1170      */
1171     public static class IpConfigurationXmlUtil {
1172 
1173         /**
1174          * List of XML tags corresponding to IpConfiguration object elements.
1175          */
1176         public static final String XML_TAG_IP_ASSIGNMENT = "IpAssignment";
1177         public static final String XML_TAG_LINK_ADDRESS = "LinkAddress";
1178         public static final String XML_TAG_LINK_PREFIX_LENGTH = "LinkPrefixLength";
1179         public static final String XML_TAG_GATEWAY_ADDRESS = "GatewayAddress";
1180         public static final String XML_TAG_DNS_SERVER_ADDRESSES = "DNSServers";
1181         public static final String XML_TAG_PROXY_SETTINGS = "ProxySettings";
1182         public static final String XML_TAG_PROXY_HOST = "ProxyHost";
1183         public static final String XML_TAG_PROXY_PORT = "ProxyPort";
1184         public static final String XML_TAG_PROXY_PAC_FILE = "ProxyPac";
1185         public static final String XML_TAG_PROXY_EXCLUSION_LIST = "ProxyExclusionList";
1186 
parseProxyExclusionListString( @ullable String exclusionListString)1187         private static List<String> parseProxyExclusionListString(
1188                 @Nullable String exclusionListString) {
1189             if (exclusionListString == null) {
1190                 return Collections.emptyList();
1191             } else {
1192                 return Arrays.asList(exclusionListString.toLowerCase(Locale.ROOT).split(","));
1193             }
1194         }
1195 
generateProxyExclusionListString(@onNull String[] exclusionList)1196         private static String generateProxyExclusionListString(@NonNull String[] exclusionList) {
1197             return TextUtils.join(",", exclusionList);
1198         }
1199 
1200         /**
1201          * Write the static IP configuration data elements to XML stream.
1202          */
writeStaticIpConfigurationToXml( XmlSerializer out, StaticIpConfiguration staticIpConfiguration)1203         private static void writeStaticIpConfigurationToXml(
1204                 XmlSerializer out, StaticIpConfiguration staticIpConfiguration)
1205                 throws XmlPullParserException, IOException {
1206             if (staticIpConfiguration.getIpAddress() != null) {
1207                 XmlUtil.writeNextValue(
1208                         out, XML_TAG_LINK_ADDRESS,
1209                         staticIpConfiguration.getIpAddress().getAddress().getHostAddress());
1210                 XmlUtil.writeNextValue(
1211                         out, XML_TAG_LINK_PREFIX_LENGTH,
1212                         staticIpConfiguration.getIpAddress().getPrefixLength());
1213             } else {
1214                 XmlUtil.writeNextValue(
1215                         out, XML_TAG_LINK_ADDRESS, null);
1216                 XmlUtil.writeNextValue(
1217                         out, XML_TAG_LINK_PREFIX_LENGTH, null);
1218             }
1219             if (staticIpConfiguration.getGateway() != null) {
1220                 XmlUtil.writeNextValue(
1221                         out, XML_TAG_GATEWAY_ADDRESS,
1222                         staticIpConfiguration.getGateway().getHostAddress());
1223             } else {
1224                 XmlUtil.writeNextValue(
1225                         out, XML_TAG_GATEWAY_ADDRESS, null);
1226 
1227             }
1228             // Create a string array of DNS server addresses
1229             String[] dnsServers = new String[staticIpConfiguration.getDnsServers().size()];
1230             int dnsServerIdx = 0;
1231             for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) {
1232                 dnsServers[dnsServerIdx++] = inetAddr.getHostAddress();
1233             }
1234             XmlUtil.writeNextValue(
1235                     out, XML_TAG_DNS_SERVER_ADDRESSES, dnsServers);
1236         }
1237 
1238         /**
1239          * Write the IP configuration data elements from the provided Configuration to the XML
1240          * stream.
1241          *
1242          * @param out             XmlSerializer instance pointing to the XML stream.
1243          * @param ipConfiguration IpConfiguration object to be serialized.
1244          */
writeToXml(XmlSerializer out, IpConfiguration ipConfiguration)1245         public static void writeToXml(XmlSerializer out, IpConfiguration ipConfiguration)
1246                 throws XmlPullParserException, IOException {
1247             // Write IP assignment settings
1248             XmlUtil.writeNextValue(out, XML_TAG_IP_ASSIGNMENT,
1249                     ipConfiguration.getIpAssignment().toString());
1250             switch (ipConfiguration.getIpAssignment()) {
1251                 case STATIC:
1252                     writeStaticIpConfigurationToXml(
1253                             out, ipConfiguration.getStaticIpConfiguration());
1254                     break;
1255                 case DHCP:
1256                 case UNASSIGNED:
1257                     break;
1258                 default:
1259                     Log.w(TAG, "Ignoring unknown ip assignment type: "
1260                             + ipConfiguration.getIpAssignment());
1261                     break;
1262             }
1263 
1264             // Write proxy settings
1265             XmlUtil.writeNextValue(
1266                     out, XML_TAG_PROXY_SETTINGS,
1267                     ipConfiguration.getProxySettings().toString());
1268             switch (ipConfiguration.getProxySettings()) {
1269                 case STATIC:
1270                     XmlUtil.writeNextValue(
1271                             out, XML_TAG_PROXY_HOST,
1272                             ipConfiguration.getHttpProxy().getHost());
1273                     XmlUtil.writeNextValue(
1274                             out, XML_TAG_PROXY_PORT,
1275                             ipConfiguration.getHttpProxy().getPort());
1276                     XmlUtil.writeNextValue(
1277                             out, XML_TAG_PROXY_EXCLUSION_LIST,
1278                             generateProxyExclusionListString(
1279                                     ipConfiguration.getHttpProxy().getExclusionList()));
1280                     break;
1281                 case PAC:
1282                     XmlUtil.writeNextValue(
1283                             out, XML_TAG_PROXY_PAC_FILE,
1284                             ipConfiguration.getHttpProxy().getPacFileUrl().toString());
1285                     break;
1286                 case NONE:
1287                 case UNASSIGNED:
1288                     break;
1289                 default:
1290                     Log.w(TAG, "Ignoring unknown proxy settings type: "
1291                             + ipConfiguration.getProxySettings());
1292                     break;
1293             }
1294         }
1295 
1296         /**
1297          * Parse out the static IP configuration from the XML stream.
1298          */
parseStaticIpConfigurationFromXml(XmlPullParser in)1299         private static StaticIpConfiguration parseStaticIpConfigurationFromXml(XmlPullParser in)
1300                 throws XmlPullParserException, IOException {
1301             StaticIpConfiguration.Builder builder = new StaticIpConfiguration.Builder();
1302 
1303             String linkAddressString =
1304                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_ADDRESS);
1305             Integer linkPrefixLength =
1306                     (Integer) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_PREFIX_LENGTH);
1307             if (linkAddressString != null && linkPrefixLength != null) {
1308                 LinkAddress linkAddress = new LinkAddress(
1309                         InetAddresses.parseNumericAddress(linkAddressString),
1310                         linkPrefixLength);
1311                 if (linkAddress.getAddress() instanceof Inet4Address) {
1312                     builder.setIpAddress(linkAddress);
1313                 } else {
1314                     Log.w(TAG, "Non-IPv4 address: " + linkAddress);
1315                 }
1316             }
1317             String gatewayAddressString =
1318                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_GATEWAY_ADDRESS);
1319             if (gatewayAddressString != null) {
1320                 InetAddress gateway =
1321                         InetAddresses.parseNumericAddress(gatewayAddressString);
1322                 RouteInfo route = new RouteInfo(null, gateway, null, RouteInfo.RTN_UNICAST);
1323                 if (route.isDefaultRoute()
1324                         && route.getDestination().getAddress() instanceof Inet4Address) {
1325                     builder.setGateway(gateway);
1326                 } else {
1327                     Log.w(TAG, "Non-IPv4 default route: " + route);
1328                 }
1329             }
1330             String[] dnsServerAddressesString =
1331                     (String[]) XmlUtil.readNextValueWithName(in, XML_TAG_DNS_SERVER_ADDRESSES);
1332             if (dnsServerAddressesString != null) {
1333                 List<InetAddress> dnsServerAddresses = new ArrayList<>();
1334                 for (String dnsServerAddressString : dnsServerAddressesString) {
1335                     InetAddress dnsServerAddress =
1336                             InetAddresses.parseNumericAddress(dnsServerAddressString);
1337                     dnsServerAddresses.add(dnsServerAddress);
1338                 }
1339                 builder.setDnsServers(dnsServerAddresses);
1340             }
1341             return builder.build();
1342         }
1343 
1344         /**
1345          * Parses the IP configuration data elements from the provided XML stream to an
1346          * IpConfiguration object.
1347          *
1348          * @param in            XmlPullParser instance pointing to the XML stream.
1349          * @param outerTagDepth depth of the outer tag in the XML document.
1350          * @return IpConfiguration object if parsing is successful, null otherwise.
1351          */
parseFromXml(XmlPullParser in, int outerTagDepth)1352         public static IpConfiguration parseFromXml(XmlPullParser in, int outerTagDepth)
1353                 throws XmlPullParserException, IOException {
1354             IpConfiguration ipConfiguration = new IpConfiguration();
1355 
1356             // Parse out the IP assignment info first.
1357             String ipAssignmentString =
1358                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_IP_ASSIGNMENT);
1359             IpAssignment ipAssignment = IpAssignment.valueOf(ipAssignmentString);
1360             ipConfiguration.setIpAssignment(ipAssignment);
1361             switch (ipAssignment) {
1362                 case STATIC:
1363                     ipConfiguration.setStaticIpConfiguration(parseStaticIpConfigurationFromXml(in));
1364                     break;
1365                 case DHCP:
1366                 case UNASSIGNED:
1367                     break;
1368                 default:
1369                     Log.w(TAG, "Ignoring unknown ip assignment type: " + ipAssignment);
1370                     break;
1371             }
1372 
1373             // Parse out the proxy settings next.
1374             String proxySettingsString =
1375                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_SETTINGS);
1376             ProxySettings proxySettings = ProxySettings.valueOf(proxySettingsString);
1377             ipConfiguration.setProxySettings(proxySettings);
1378             switch (proxySettings) {
1379                 case STATIC:
1380                     String proxyHost =
1381                             (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_HOST);
1382                     int proxyPort =
1383                             (int) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PORT);
1384                     String proxyExclusionList =
1385                             (String) XmlUtil.readNextValueWithName(
1386                                     in, XML_TAG_PROXY_EXCLUSION_LIST);
1387                     ipConfiguration.setHttpProxy(
1388                             ProxyInfo.buildDirectProxy(
1389                                     proxyHost, proxyPort,
1390                                     parseProxyExclusionListString(proxyExclusionList)));
1391                     break;
1392                 case PAC:
1393                     String proxyPacFile =
1394                             (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PAC_FILE);
1395                     ipConfiguration.setHttpProxy(
1396                             ProxyInfo.buildPacProxy(Uri.parse(proxyPacFile)));
1397                     break;
1398                 case NONE:
1399                 case UNASSIGNED:
1400                     break;
1401                 default:
1402                     Log.w(TAG, "Ignoring unknown proxy settings type: " + proxySettings);
1403                     break;
1404             }
1405             return ipConfiguration;
1406         }
1407     }
1408 
1409     /**
1410      * Utility class to serialize and deserialize {@link NetworkSelectionStatus} object to XML &
1411      * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module.
1412      */
1413     public static class NetworkSelectionStatusXmlUtil {
1414 
1415         /**
1416          * List of XML tags corresponding to NetworkSelectionStatus object elements.
1417          */
1418         public static final String XML_TAG_SELECTION_STATUS = "SelectionStatus";
1419         public static final String XML_TAG_DISABLE_REASON = "DisableReason";
1420         public static final String XML_TAG_CONNECT_CHOICE = "ConnectChoice";
1421         public static final String XML_TAG_HAS_EVER_CONNECTED = "HasEverConnected";
1422         public static final String XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED =
1423                 "CaptivePortalNeverDetected";
1424         public static final String XML_TAG_HAS_EVER_VALIDATED_INTERNET_ACCESS =
1425                 "HasEverValidatedInternetAccess";
1426         public static final String XML_TAG_CONNECT_CHOICE_RSSI = "ConnectChoiceRssi";
1427 
1428         /**
1429          * Write the NetworkSelectionStatus data elements from the provided status to the XML
1430          * stream.
1431          *
1432          * @param out             XmlSerializer instance pointing to the XML stream.
1433          * @param selectionStatus NetworkSelectionStatus object to be serialized.
1434          */
writeToXml(XmlSerializer out, NetworkSelectionStatus selectionStatus)1435         public static void writeToXml(XmlSerializer out, NetworkSelectionStatus selectionStatus)
1436                 throws XmlPullParserException, IOException {
1437             XmlUtil.writeNextValue(
1438                     out, XML_TAG_SELECTION_STATUS, selectionStatus.getNetworkStatusString());
1439             XmlUtil.writeNextValue(
1440                     out, XML_TAG_DISABLE_REASON,
1441                     selectionStatus.getNetworkSelectionDisableReasonString());
1442             XmlUtil.writeNextValue(out, XML_TAG_CONNECT_CHOICE, selectionStatus.getConnectChoice());
1443             XmlUtil.writeNextValue(out, XML_TAG_CONNECT_CHOICE_RSSI,
1444                     selectionStatus.getConnectChoiceRssi());
1445             XmlUtil.writeNextValue(
1446                     out, XML_TAG_HAS_EVER_CONNECTED, selectionStatus.hasEverConnected());
1447             XmlUtil.writeNextValue(out, XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED,
1448                     selectionStatus.hasNeverDetectedCaptivePortal());
1449             XmlUtil.writeNextValue(out, XML_TAG_HAS_EVER_VALIDATED_INTERNET_ACCESS,
1450                     selectionStatus.hasEverValidatedInternetAccess());
1451         }
1452 
1453         /**
1454          * Parses the NetworkSelectionStatus data elements from the provided XML stream to a
1455          * NetworkSelectionStatus object.
1456          *
1457          * @param in            XmlPullParser instance pointing to the XML stream.
1458          * @param outerTagDepth depth of the outer tag in the XML document.
1459          * @return NetworkSelectionStatus object if parsing is successful, null otherwise.
1460          */
parseFromXml(XmlPullParser in, int outerTagDepth)1461         public static NetworkSelectionStatus parseFromXml(XmlPullParser in, int outerTagDepth)
1462                 throws XmlPullParserException, IOException {
1463             NetworkSelectionStatus selectionStatus = new NetworkSelectionStatus();
1464             String statusString = "";
1465             String disableReasonString = "";
1466             // Initialize hasNeverDetectedCaptivePortal to "false" for upgrading legacy configs
1467             // which do not have the XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED tag.
1468             selectionStatus.setHasNeverDetectedCaptivePortal(false);
1469 
1470             // Initialize hasEverValidatedInternetAccess to "true" for existing configs which don't
1471             // have any value stored.
1472             selectionStatus.setHasEverValidatedInternetAccess(true);
1473 
1474             // Loop through and parse out all the elements from the stream within this section.
1475             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1476                 String[] valueName = new String[1];
1477                 Object value = XmlUtil.readCurrentValue(in, valueName);
1478                 if (valueName[0] == null) {
1479                     throw new XmlPullParserException("Missing value name");
1480                 }
1481                 switch (valueName[0]) {
1482                     case XML_TAG_SELECTION_STATUS:
1483                         statusString = (String) value;
1484                         break;
1485                     case XML_TAG_DISABLE_REASON:
1486                         disableReasonString = (String) value;
1487                         break;
1488                     case XML_TAG_CONNECT_CHOICE:
1489                         selectionStatus.setConnectChoice((String) value);
1490                         break;
1491                     case XML_TAG_CONNECT_CHOICE_RSSI:
1492                         selectionStatus.setConnectChoiceRssi((int) value);
1493                         break;
1494                     case XML_TAG_HAS_EVER_CONNECTED:
1495                         selectionStatus.setHasEverConnected((boolean) value);
1496                         break;
1497                     case XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED:
1498                         selectionStatus.setHasNeverDetectedCaptivePortal((boolean) value);
1499                         break;
1500                     case XML_TAG_HAS_EVER_VALIDATED_INTERNET_ACCESS:
1501                         selectionStatus.setHasEverValidatedInternetAccess((boolean) value);
1502                         break;
1503                     default:
1504                         Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]);
1505                         break;
1506                 }
1507             }
1508             // Now figure out the network selection status codes from |selectionStatusString| &
1509             // |disableReasonString|.
1510             int status =
1511                     Arrays.asList(NetworkSelectionStatus.QUALITY_NETWORK_SELECTION_STATUS)
1512                             .indexOf(statusString);
1513             int disableReason =
1514                     NetworkSelectionStatus.getDisableReasonByString(disableReasonString);
1515 
1516             // If either of the above codes are invalid or if the network was temporarily disabled
1517             // (blacklisted), restore the status as enabled. We don't want to persist blacklists
1518             // across reboots.
1519             if (status == -1 || disableReason == -1 ||
1520                     status == NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED) {
1521                 status = NetworkSelectionStatus.NETWORK_SELECTION_ENABLED;
1522                 disableReason = NetworkSelectionStatus.DISABLED_NONE;
1523             }
1524             selectionStatus.setNetworkSelectionStatus(status);
1525             selectionStatus.setNetworkSelectionDisableReason(disableReason);
1526             if (status == NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED) {
1527                 // Make the counter non-zero so that logging code works properly
1528                 selectionStatus.setDisableReasonCounter(disableReason, 1);
1529             }
1530             return selectionStatus;
1531         }
1532     }
1533 
1534     /**
1535      * Utility class to serialize and deseriaize {@link WifiEnterpriseConfig} object to XML &
1536      * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module.
1537      */
1538     public static class WifiEnterpriseConfigXmlUtil {
1539 
1540         /**
1541          * List of XML tags corresponding to WifiEnterpriseConfig object elements.
1542          */
1543         public static final String XML_TAG_IDENTITY = "Identity";
1544         public static final String XML_TAG_ANON_IDENTITY = "AnonIdentity";
1545         public static final String XML_TAG_PASSWORD = "Password";
1546         public static final String XML_TAG_CLIENT_CERT = "ClientCert";
1547         public static final String XML_TAG_CA_CERT = "CaCert";
1548         public static final String XML_TAG_SUBJECT_MATCH = "SubjectMatch";
1549         public static final String XML_TAG_ENGINE = "Engine";
1550         public static final String XML_TAG_ENGINE_ID = "EngineId";
1551         public static final String XML_TAG_PRIVATE_KEY_ID = "PrivateKeyId";
1552         public static final String XML_TAG_ALT_SUBJECT_MATCH = "AltSubjectMatch";
1553         public static final String XML_TAG_DOM_SUFFIX_MATCH = "DomSuffixMatch";
1554         public static final String XML_TAG_CA_PATH = "CaPath";
1555         public static final String XML_TAG_EAP_METHOD = "EapMethod";
1556         public static final String XML_TAG_PHASE2_METHOD = "Phase2Method";
1557         public static final String XML_TAG_PLMN = "PLMN";
1558         public static final String XML_TAG_REALM = "Realm";
1559         public static final String XML_TAG_OCSP = "Ocsp";
1560         public static final String XML_TAG_WAPI_CERT_SUITE = "WapiCertSuite";
1561         public static final String XML_TAG_APP_INSTALLED_ROOT_CA_CERT = "AppInstalledRootCaCert";
1562         public static final String XML_TAG_APP_INSTALLED_PRIVATE_KEY = "AppInstalledPrivateKey";
1563         public static final String XML_TAG_KEYCHAIN_KEY_ALIAS = "KeyChainAlias";
1564         public static final String XML_TAG_DECORATED_IDENTITY_PREFIX = "DecoratedIdentityPrefix";
1565         public static final String XML_TAG_TRUST_ON_FIRST_USE = "TrustOnFirstUse";
1566         public static final String XML_TAG_USER_APPROVE_NO_CA_CERT = "UserApproveNoCaCert";
1567         public static final String XML_TAG_MINIMUM_TLS_VERSION = "MinimumTlsVersion";
1568         public static final String XML_TAG_TOFU_DIALOG_STATE = "TofuDialogState";
1569         public static final String XML_TAG_TOFU_CONNECTION_STATE = "TofuConnectionState";
1570 
1571         /**
1572          * Write password key to the XML stream.
1573          *
1574          * If encryptionUtil is null or if encryption fails for some reason, the password is stored
1575          * in plaintext, else the encrypted psk is stored.
1576          */
writePasswordToXml( XmlSerializer out, String password, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)1577         private static void writePasswordToXml(
1578                 XmlSerializer out, String password,
1579                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
1580                 throws XmlPullParserException, IOException {
1581             EncryptedData encryptedData = null;
1582             if (encryptionUtil != null) {
1583                 if (password != null) {
1584                     encryptedData = encryptionUtil.encrypt(password.getBytes());
1585                     if (encryptedData == null) {
1586                         // We silently fail encryption failures!
1587                         Log.wtf(TAG, "Encryption of password failed");
1588                     }
1589                 }
1590             }
1591             if (encryptedData != null) {
1592                 XmlUtil.writeNextSectionStart(out, XML_TAG_PASSWORD);
1593                 EncryptedDataXmlUtil.writeToXml(out, encryptedData);
1594                 XmlUtil.writeNextSectionEnd(out, XML_TAG_PASSWORD);
1595             } else {
1596                 XmlUtil.writeNextValue(out, XML_TAG_PASSWORD, password);
1597             }
1598         }
1599 
1600         /**
1601          * Write the WifiEnterpriseConfig data elements from the provided config to the XML
1602          * stream.
1603          *
1604          * @param out XmlSerializer instance pointing to the XML stream.
1605          * @param enterpriseConfig WifiEnterpriseConfig object to be serialized.
1606          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}.
1607          */
writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)1608         public static void writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig,
1609                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
1610                 throws XmlPullParserException, IOException {
1611             XmlUtil.writeNextValue(out, XML_TAG_IDENTITY,
1612                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.IDENTITY_KEY));
1613             XmlUtil.writeNextValue(out, XML_TAG_ANON_IDENTITY,
1614                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ANON_IDENTITY_KEY));
1615             writePasswordToXml(
1616                     out, enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PASSWORD_KEY),
1617                     encryptionUtil);
1618             XmlUtil.writeNextValue(out, XML_TAG_CLIENT_CERT,
1619                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CLIENT_CERT_KEY));
1620             XmlUtil.writeNextValue(out, XML_TAG_CA_CERT,
1621                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_CERT_KEY));
1622             XmlUtil.writeNextValue(out, XML_TAG_SUBJECT_MATCH,
1623                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.SUBJECT_MATCH_KEY));
1624             XmlUtil.writeNextValue(out, XML_TAG_ENGINE,
1625                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY));
1626             XmlUtil.writeNextValue(out, XML_TAG_ENGINE_ID,
1627                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY));
1628             XmlUtil.writeNextValue(out, XML_TAG_PRIVATE_KEY_ID,
1629                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY));
1630             XmlUtil.writeNextValue(out, XML_TAG_ALT_SUBJECT_MATCH,
1631                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY));
1632             XmlUtil.writeNextValue(out, XML_TAG_DOM_SUFFIX_MATCH,
1633                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY));
1634             XmlUtil.writeNextValue(out, XML_TAG_CA_PATH,
1635                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_PATH_KEY));
1636             XmlUtil.writeNextValue(out, XML_TAG_EAP_METHOD, enterpriseConfig.getEapMethod());
1637             XmlUtil.writeNextValue(out, XML_TAG_PHASE2_METHOD, enterpriseConfig.getPhase2Method());
1638             XmlUtil.writeNextValue(out, XML_TAG_PLMN, enterpriseConfig.getPlmn());
1639             XmlUtil.writeNextValue(out, XML_TAG_REALM, enterpriseConfig.getRealm());
1640             XmlUtil.writeNextValue(out, XML_TAG_OCSP, enterpriseConfig.getOcsp());
1641             XmlUtil.writeNextValue(out,
1642                     XML_TAG_WAPI_CERT_SUITE, enterpriseConfig.getWapiCertSuite());
1643             XmlUtil.writeNextValue(out, XML_TAG_APP_INSTALLED_ROOT_CA_CERT,
1644                     enterpriseConfig.isAppInstalledCaCert());
1645             XmlUtil.writeNextValue(out, XML_TAG_APP_INSTALLED_PRIVATE_KEY,
1646                     enterpriseConfig.isAppInstalledDeviceKeyAndCert());
1647             XmlUtil.writeNextValue(out, XML_TAG_KEYCHAIN_KEY_ALIAS,
1648                     enterpriseConfig.getClientKeyPairAliasInternal());
1649             if (SdkLevel.isAtLeastS()) {
1650                 XmlUtil.writeNextValue(out, XML_TAG_DECORATED_IDENTITY_PREFIX,
1651                         enterpriseConfig.getDecoratedIdentityPrefix());
1652             }
1653             XmlUtil.writeNextValue(out, XML_TAG_TRUST_ON_FIRST_USE,
1654                     enterpriseConfig.isTrustOnFirstUseEnabled());
1655             XmlUtil.writeNextValue(out, XML_TAG_USER_APPROVE_NO_CA_CERT,
1656                     enterpriseConfig.isUserApproveNoCaCert());
1657             XmlUtil.writeNextValue(out, XML_TAG_MINIMUM_TLS_VERSION,
1658                     enterpriseConfig.getMinimumTlsVersion());
1659             XmlUtil.writeNextValue(out, XML_TAG_TOFU_DIALOG_STATE,
1660                     enterpriseConfig.getTofuDialogState());
1661             XmlUtil.writeNextValue(out, XML_TAG_TOFU_CONNECTION_STATE,
1662                     enterpriseConfig.getTofuConnectionState());
1663         }
1664 
1665         /**
1666          * Parses the data elements from the provided XML stream to a WifiEnterpriseConfig object.
1667          *
1668          * @param in XmlPullParser instance pointing to the XML stream.
1669          * @param outerTagDepth depth of the outer tag in the XML document.
1670          * @param shouldExpectEncryptedCredentials Whether to expect encrypted credentials or not.
1671          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}.
1672          * @return WifiEnterpriseConfig object if parsing is successful, null otherwise.
1673          */
parseFromXml(XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)1674         public static WifiEnterpriseConfig parseFromXml(XmlPullParser in, int outerTagDepth,
1675                 boolean shouldExpectEncryptedCredentials,
1676                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
1677                 throws XmlPullParserException, IOException {
1678             WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
1679 
1680             // Loop through and parse out all the elements from the stream within this section.
1681             while (XmlUtilHelper.nextElementWithin(in, outerTagDepth)) {
1682                 if (in.getAttributeValue(null, "name") != null) {
1683                     // Value elements.
1684                     String[] valueName = new String[1];
1685                     Object value = XmlUtil.readCurrentValue(in, valueName);
1686                     if (valueName[0] == null) {
1687                         throw new XmlPullParserException("Missing value name");
1688                     }
1689                     switch (valueName[0]) {
1690                         case XML_TAG_IDENTITY:
1691                             enterpriseConfig.setFieldValue(
1692                                     WifiEnterpriseConfig.IDENTITY_KEY, (String) value);
1693                             break;
1694                         case XML_TAG_ANON_IDENTITY:
1695                             enterpriseConfig.setFieldValue(
1696                                     WifiEnterpriseConfig.ANON_IDENTITY_KEY, (String) value);
1697                             break;
1698                         case XML_TAG_PASSWORD:
1699                             enterpriseConfig.setFieldValue(
1700                                     WifiEnterpriseConfig.PASSWORD_KEY, (String) value);
1701                             if (shouldExpectEncryptedCredentials
1702                                     && !TextUtils.isEmpty(enterpriseConfig.getFieldValue(
1703                                     WifiEnterpriseConfig.PASSWORD_KEY))) {
1704                                 // Indicates that encryption of password failed when it was last
1705                                 // written.
1706                                 Log.e(TAG, "password value not expected");
1707                             }
1708                             break;
1709                         case XML_TAG_CLIENT_CERT:
1710                             enterpriseConfig.setFieldValue(
1711                                     WifiEnterpriseConfig.CLIENT_CERT_KEY, (String) value);
1712                             break;
1713                         case XML_TAG_CA_CERT:
1714                             enterpriseConfig.setFieldValue(
1715                                     WifiEnterpriseConfig.CA_CERT_KEY, (String) value);
1716                             break;
1717                         case XML_TAG_SUBJECT_MATCH:
1718                             enterpriseConfig.setFieldValue(
1719                                     WifiEnterpriseConfig.SUBJECT_MATCH_KEY, (String) value);
1720                             break;
1721                         case XML_TAG_ENGINE:
1722                             enterpriseConfig.setFieldValue(
1723                                     WifiEnterpriseConfig.ENGINE_KEY, (String) value);
1724                             break;
1725                         case XML_TAG_ENGINE_ID:
1726                             enterpriseConfig.setFieldValue(
1727                                     WifiEnterpriseConfig.ENGINE_ID_KEY, (String) value);
1728                             break;
1729                         case XML_TAG_PRIVATE_KEY_ID:
1730                             enterpriseConfig.setFieldValue(
1731                                     WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, (String) value);
1732                             break;
1733                         case XML_TAG_ALT_SUBJECT_MATCH:
1734                             enterpriseConfig.setFieldValue(
1735                                     WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, (String) value);
1736                             break;
1737                         case XML_TAG_DOM_SUFFIX_MATCH:
1738                             enterpriseConfig.setFieldValue(
1739                                     WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY, (String) value);
1740                             break;
1741                         case XML_TAG_CA_PATH:
1742                             enterpriseConfig.setFieldValue(
1743                                     WifiEnterpriseConfig.CA_PATH_KEY, (String) value);
1744                             break;
1745                         case XML_TAG_OCSP:
1746                             enterpriseConfig.setOcsp((int) value);
1747                             break;
1748                         case XML_TAG_EAP_METHOD:
1749                             enterpriseConfig.setEapMethod((int) value);
1750                             break;
1751                         case XML_TAG_PHASE2_METHOD:
1752                             enterpriseConfig.setPhase2Method((int) value);
1753                             break;
1754                         case XML_TAG_PLMN:
1755                             enterpriseConfig.setPlmn((String) value);
1756                             break;
1757                         case XML_TAG_REALM:
1758                             enterpriseConfig.setRealm((String) value);
1759                             break;
1760                         case XML_TAG_WAPI_CERT_SUITE:
1761                             enterpriseConfig.setWapiCertSuite((String) value);
1762                             break;
1763                         case XML_TAG_APP_INSTALLED_ROOT_CA_CERT:
1764                             enterpriseConfig.initIsAppInstalledCaCert((boolean) value);
1765                             break;
1766                         case XML_TAG_APP_INSTALLED_PRIVATE_KEY:
1767                             enterpriseConfig.initIsAppInstalledDeviceKeyAndCert((boolean) value);
1768                             break;
1769                         case XML_TAG_KEYCHAIN_KEY_ALIAS:
1770                             if (SdkLevel.isAtLeastS()) {
1771                                 enterpriseConfig.setClientKeyPairAlias((String) value);
1772                             }
1773                             break;
1774                         case XML_TAG_DECORATED_IDENTITY_PREFIX:
1775                             if (SdkLevel.isAtLeastS()) {
1776                                 enterpriseConfig.setDecoratedIdentityPrefix((String) value);
1777                             }
1778                             break;
1779                         case XML_TAG_TRUST_ON_FIRST_USE:
1780                             enterpriseConfig.enableTrustOnFirstUse((boolean) value);
1781                             break;
1782                         case XML_TAG_USER_APPROVE_NO_CA_CERT:
1783                             enterpriseConfig.setUserApproveNoCaCert((boolean) value);
1784                             break;
1785                         case XML_TAG_MINIMUM_TLS_VERSION:
1786                             enterpriseConfig.setMinimumTlsVersion((int) value);
1787                             break;
1788                         case XML_TAG_TOFU_DIALOG_STATE:
1789                             enterpriseConfig.setTofuDialogState((int) value);
1790                             break;
1791                         case XML_TAG_TOFU_CONNECTION_STATE:
1792                             enterpriseConfig.setTofuConnectionState((int) value);
1793                             break;
1794                         default:
1795                             Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]);
1796                             break;
1797                     }
1798                 } else {
1799                     String tagName = in.getName();
1800                     if (tagName == null) {
1801                         throw new XmlPullParserException("Unexpected null tag found");
1802                     }
1803                     switch (tagName) {
1804                         case XML_TAG_PASSWORD:
1805                             if (!shouldExpectEncryptedCredentials || encryptionUtil == null) {
1806                                 throw new XmlPullParserException(
1807                                         "encrypted password section not expected");
1808                             }
1809                             EncryptedData encryptedData =
1810                                     EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1);
1811                             byte[] passwordBytes = encryptionUtil.decrypt(encryptedData);
1812                             if (passwordBytes == null) {
1813                                 Log.wtf(TAG, "Decryption of password failed");
1814                             } else {
1815                                 enterpriseConfig.setFieldValue(
1816                                         WifiEnterpriseConfig.PASSWORD_KEY,
1817                                         new String(passwordBytes));
1818                             }
1819                             break;
1820                         default:
1821                             Log.w(TAG, "Ignoring unknown tag name found: " + tagName);
1822                             break;
1823                     }
1824                 }
1825             }
1826             return enterpriseConfig;
1827         }
1828     }
1829 
1830     /**
1831      * Utility class to serialize and deseriaize {@link EncryptedData} object to XML &
1832      * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module.
1833      */
1834     public static class EncryptedDataXmlUtil {
1835         /**
1836          * List of XML tags corresponding to EncryptedData object elements.
1837          */
1838         private static final String XML_TAG_ENCRYPTED_DATA = "EncryptedData";
1839         private static final String XML_TAG_IV = "IV";
1840 
1841         /**
1842          * Write the NetworkSelectionStatus data elements from the provided status to the XML
1843          * stream.
1844          *
1845          * @param out           XmlSerializer instance pointing to the XML stream.
1846          * @param encryptedData EncryptedData object to be serialized.
1847          */
writeToXml(XmlSerializer out, EncryptedData encryptedData)1848         public static void writeToXml(XmlSerializer out, EncryptedData encryptedData)
1849                 throws XmlPullParserException, IOException {
1850             XmlUtil.writeNextValue(
1851                     out, XML_TAG_ENCRYPTED_DATA, encryptedData.getEncryptedData());
1852             XmlUtil.writeNextValue(out, XML_TAG_IV, encryptedData.getIv());
1853         }
1854 
1855         /**
1856          * Parses the EncryptedData data elements from the provided XML stream to a
1857          * EncryptedData object.
1858          *
1859          * @param in            XmlPullParser instance pointing to the XML stream.
1860          * @param outerTagDepth depth of the outer tag in the XML document.
1861          * @return EncryptedData object if parsing is successful, null otherwise.
1862          */
parseFromXml(XmlPullParser in, int outerTagDepth)1863         public static EncryptedData parseFromXml(XmlPullParser in, int outerTagDepth)
1864                 throws XmlPullParserException, IOException {
1865             byte[] encryptedData = null;
1866             byte[] iv = null;
1867 
1868             // Loop through and parse out all the elements from the stream within this section.
1869             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1870                 String[] valueName = new String[1];
1871                 Object value = XmlUtil.readCurrentValue(in, valueName);
1872                 if (valueName[0] == null) {
1873                     throw new XmlPullParserException("Missing value name");
1874                 }
1875                 switch (valueName[0]) {
1876                     case XML_TAG_ENCRYPTED_DATA:
1877                         encryptedData = (byte[]) value;
1878                         break;
1879                     case XML_TAG_IV:
1880                         iv = (byte[]) value;
1881                         break;
1882                     default:
1883                         Log.e(TAG, "Unknown value name found: " + valueName[0]);
1884                         break;
1885                 }
1886             }
1887             return new EncryptedData(encryptedData, iv);
1888         }
1889 
1890         /**
1891          * Parses the EncryptedData data elements arrays from the provided XML stream to a list of
1892          * EncryptedData object.
1893          *
1894          * @param in            XmlPullParser instance pointing to the XML stream.
1895          * @param outerTagDepth depth of the outer tag in the XML document.
1896          * @return List of encryptedData object if parsing is successful, empty otherwise.
1897          */
parseListFromXml(XmlPullParser in, int outerTagDepth)1898         public static @NonNull List<EncryptedData> parseListFromXml(XmlPullParser in,
1899                 int outerTagDepth) throws XmlPullParserException, IOException {
1900             List<EncryptedData> encryptedDataList = new ArrayList<>();
1901             // Loop through and parse out all the elements from the stream within this section.
1902             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1903                 if (in.getAttributeValue(null, "name") != null) {
1904                     String[] valueName = new String[1];
1905                     Object value = XmlUtil.readCurrentValue(in, valueName);
1906                     if (valueName[0] == null) {
1907                         throw new XmlPullParserException("Missing value name");
1908                     }
1909                     byte[] encryptedData;
1910                     byte[] iv;
1911                     if (XML_TAG_ENCRYPTED_DATA.equals(valueName[0])) {
1912                         encryptedData = (byte[]) value;
1913                         if (!XmlUtil.isNextSectionEnd(in, outerTagDepth) && in.getAttributeValue(
1914                                 null, "name") != null) {
1915                             value = XmlUtil.readCurrentValue(in, valueName);
1916                             if (valueName[0] == null) {
1917                                 throw new XmlPullParserException("Missing value name");
1918                             }
1919                             if (XML_TAG_IV.equals(valueName[0])) {
1920                                 iv = (byte[]) value;
1921                                 encryptedDataList.add(new EncryptedData(encryptedData, iv));
1922                             }
1923                         }
1924                     }
1925                 }
1926             }
1927             return encryptedDataList;
1928         }
1929     }
1930 
nextElementWithin(XmlPullParser parser, int outerDepth)1931     public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
1932             throws IOException, XmlPullParserException {
1933         return XmlUtilHelper.nextElementWithin(parser, outerDepth);
1934     }
1935 
1936     /**
1937      * Utility class to serialize and deseriaize {@link SoftApConfiguration} object to XML
1938      * & vice versa. This is used by both {@link com.android.server.wifi.SoftApStore}  modules.
1939      */
1940     public static class SoftApConfigurationXmlUtil {
1941         /**
1942          * List of XML tags corresponding to SoftApConfiguration object elements.
1943          */
1944         public static final String XML_TAG_CLIENT_MACADDRESS = "ClientMacAddress";
1945         public static final String XML_TAG_BAND_CHANNEL = "BandChannel";
1946         public static final String XML_TAG_SSID = "SSID"; // Use XML_TAG_WIFI_SSID instead
1947         public static final String XML_TAG_WIFI_SSID = "WifiSsid";
1948         public static final String XML_TAG_BSSID = "Bssid";
1949         public static final String XML_TAG_BAND = "Band";
1950         public static final String XML_TAG_CHANNEL = "Channel";
1951         public static final String XML_TAG_HIDDEN_SSID = "HiddenSSID";
1952         public static final String XML_TAG_SECURITY_TYPE = "SecurityType";
1953         public static final String XML_TAG_WPA2_PASSPHRASE = "Wpa2Passphrase";
1954         public static final String XML_TAG_AP_BAND = "ApBand";
1955         public static final String XML_TAG_PASSPHRASE = "Passphrase";
1956         public static final String XML_TAG_MAX_NUMBER_OF_CLIENTS = "MaxNumberOfClients";
1957         public static final String XML_TAG_AUTO_SHUTDOWN_ENABLED = "AutoShutdownEnabled";
1958         public static final String XML_TAG_SHUTDOWN_TIMEOUT_MILLIS = "ShutdownTimeoutMillis";
1959         public static final String XML_TAG_CLIENT_CONTROL_BY_USER = "ClientControlByUser";
1960         public static final String XML_TAG_BLOCKED_CLIENT_LIST = "BlockedClientList";
1961         public static final String XML_TAG_ALLOWED_CLIENT_LIST = "AllowedClientList";
1962         public static final String XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_ENABLED =
1963                 "BridgedModeOpportunisticShutdownEnabled";
1964         public static final String XML_TAG_MAC_RAMDOMIZATION_SETTING = "MacRandomizationSetting";
1965         public static final String XML_TAG_BAND_CHANNEL_MAP = "BandChannelMap";
1966         public static final String XML_TAG_80211_AX_ENABLED = "80211axEnabled";
1967         public static final String XML_TAG_80211_BE_ENABLED = "80211beEnabled";
1968         public static final String XML_TAG_USER_CONFIGURATION = "UserConfiguration";
1969         public static final String XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_TIMEOUT_MILLIS =
1970                 "BridgedModeOpportunisticShutdownTimeoutMillis";
1971         public static final String XML_TAG_VENDOR_ELEMENT = "VendorElement";
1972         public static final String XML_TAG_VENDOR_ELEMENTS = "VendorElements";
1973         public static final String XML_TAG_PERSISTENT_RANDOMIZED_MAC_ADDRESS =
1974                 "PersistentRandomizedMacAddress";
1975 
1976 
1977         /**
1978          * Parses the client list from the provided XML stream to a ArrayList object.
1979          *
1980          * @param in            XmlPullParser instance pointing to the XML stream.
1981          * @param outerTagDepth depth of the outer tag in the XML document.
1982          * @return ArrayList object if parsing is successful, null otherwise.
1983          */
parseClientListFromXml(XmlPullParser in, int outerTagDepth)1984         public static List<MacAddress> parseClientListFromXml(XmlPullParser in,
1985                 int outerTagDepth) throws XmlPullParserException, IOException,
1986                 IllegalArgumentException {
1987             List<MacAddress> clientList = new ArrayList<>();
1988             // Loop through and parse out all the elements from the stream within this section.
1989             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1990                 String[] valueName = new String[1];
1991                 Object value = XmlUtil.readCurrentValue(in, valueName);
1992                 if (valueName[0] == null) {
1993                     throw new XmlPullParserException("Missing value name");
1994                 }
1995                 switch (valueName[0]) {
1996                     case XML_TAG_CLIENT_MACADDRESS:
1997                         MacAddress client = MacAddress.fromString((String) value);
1998                         clientList.add(client);
1999                         break;
2000                     default:
2001                         Log.e(TAG, "Unknown value name found: " + valueName[0]);
2002                         break;
2003                 }
2004             }
2005             return clientList;
2006         }
2007 
2008         /**
2009          * Write the SoftApConfiguration client control list data elements
2010          * from the provided list to the XML stream.
2011          *
2012          * @param out           XmlSerializer instance pointing to the XML stream.
2013          * @param clientList Client list object to be serialized.
2014          */
writeClientListToXml(XmlSerializer out, List<MacAddress> clientList)2015         public static void writeClientListToXml(XmlSerializer out, List<MacAddress> clientList)
2016                 throws XmlPullParserException, IOException {
2017             for (MacAddress mac: clientList) {
2018                 XmlUtil.writeNextValue(out, XML_TAG_CLIENT_MACADDRESS, mac.toString());
2019             }
2020         }
2021 
2022         /**
2023          * Write the SoftApConfiguration vendor elements list information elements to the XML
2024          *
2025          * @param out XmlSerializer instance pointing to the XML stream
2026          * @param elements Vendor elements list
2027          */
writeVendorElementsSetToXml( XmlSerializer out, List<ScanResult.InformationElement> elements)2028         public static void writeVendorElementsSetToXml(
2029                 XmlSerializer out, List<ScanResult.InformationElement> elements)
2030                 throws XmlPullParserException, IOException {
2031             for (ScanResult.InformationElement e : elements) {
2032                 XmlUtil.writeNextValue(out, XML_TAG_VENDOR_ELEMENT,
2033                         InformationElementUtil.toHexString(e));
2034             }
2035         }
2036 
2037         /**
2038          * Parses the vendor elements from the provided XML stream to HashSet object.
2039          *
2040          * @param in XmlPullParser instance pointing to the XML stream
2041          * @param outerTagDepth depth of the outer tag in the XML document
2042          * @return HashSet object if parsing is successful, empty set otherwise
2043          */
parseVendorElementsFromXml( XmlPullParser in, int outerTagDepth)2044         public static List<ScanResult.InformationElement> parseVendorElementsFromXml(
2045                 XmlPullParser in, int outerTagDepth)
2046                 throws XmlPullParserException, IOException, IllegalArgumentException {
2047             List<ScanResult.InformationElement> elements = new ArrayList<>();
2048             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
2049                 String[] valueName = new String[1];
2050                 Object value = XmlUtil.readCurrentValue(in, valueName);
2051                 if (valueName[0] == null) {
2052                     throw new XmlPullParserException("Missing value name");
2053                 }
2054                 if (XML_TAG_VENDOR_ELEMENT.equals(valueName[0])) {
2055                     ScanResult.InformationElement[] data =
2056                             InformationElementUtil.parseInformationElements((String) value);
2057                     elements.addAll(Arrays.asList(data));
2058                 } else {
2059                     Log.e(TAG, "Unknown value name found: " + valueName[0]);
2060                 }
2061             }
2062             return elements;
2063         }
2064 
2065         /**
2066          * Parses the band and channel from the provided XML stream to a SparseIntArray object.
2067          *
2068          * @param in            XmlPullParser instance pointing to the XML stream.
2069          * @param outerTagDepth depth of the outer tag in the XML document.
2070          * @return SparseIntArray object if parsing is successful, null otherwise.
2071          */
parseChannelsFromXml(XmlPullParser in, int outerTagDepth)2072         public static SparseIntArray parseChannelsFromXml(XmlPullParser in,
2073                 int outerTagDepth) throws XmlPullParserException, IOException,
2074                 IllegalArgumentException {
2075             SparseIntArray channels = new SparseIntArray();
2076             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
2077                 int band = ApConfigUtil.INVALID_VALUE_FOR_BAND_OR_CHANNEL;
2078                 int channel = ApConfigUtil.INVALID_VALUE_FOR_BAND_OR_CHANNEL;
2079                 switch (in.getName()) {
2080                     case XML_TAG_BAND_CHANNEL:
2081                         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth + 1)) {
2082                             String[] valueName = new String[1];
2083                             Object value = XmlUtil.readCurrentValue(in, valueName);
2084                             if (valueName[0] == null) {
2085                                 throw new XmlPullParserException("Missing value name");
2086                             }
2087                             switch (valueName[0]) {
2088                                 case XML_TAG_BAND:
2089                                     band = (int) value;
2090                                     break;
2091                                 case XML_TAG_CHANNEL:
2092                                     channel = (int) value;
2093                                     break;
2094                                 default:
2095                                     Log.e(TAG, "Unknown value name found: " + valueName[0]);
2096                                     break;
2097                             }
2098                         }
2099                         channels.put(band, channel);
2100                         break;
2101                 }
2102             }
2103             return channels;
2104         }
2105 
2106         /**
2107          * Write the SoftApConfiguration channels data elements
2108          * from the provided SparseIntArray to the XML stream.
2109          *
2110          * @param out       XmlSerializer instance pointing to the XML stream.
2111          * @param channels  SparseIntArray, which includes bands and channels, to be serialized.
2112          */
writeChannelsToXml(XmlSerializer out, SparseIntArray channels)2113         public static void writeChannelsToXml(XmlSerializer out, SparseIntArray channels)
2114                 throws XmlPullParserException, IOException {
2115             for (int i = 0; i < channels.size(); i++) {
2116                 XmlUtil.writeNextSectionStart(out, XML_TAG_BAND_CHANNEL);
2117                 XmlUtil.writeNextValue(out, XML_TAG_BAND, channels.keyAt(i));
2118                 XmlUtil.writeNextValue(out, XML_TAG_CHANNEL, channels.valueAt(i));
2119                 XmlUtil.writeNextSectionEnd(out, XML_TAG_BAND_CHANNEL);
2120             }
2121         }
2122 
2123         /**
2124          * Write the SoftApConfiguration data elements to the XML stream.
2125          *
2126          * @param out          XmlSerializer instance pointing to the XML stream.
2127          * @param softApConfig configuration of the Soft AP.
2128          */
writeSoftApConfigurationToXml(@onNull XmlSerializer out, @NonNull SoftApConfiguration softApConfig, WifiConfigStoreEncryptionUtil encryptionUtil)2129         public static void writeSoftApConfigurationToXml(@NonNull XmlSerializer out,
2130                 @NonNull SoftApConfiguration softApConfig,
2131                 WifiConfigStoreEncryptionUtil encryptionUtil)
2132                 throws XmlPullParserException, IOException {
2133             if (softApConfig.getWifiSsid() != null) {
2134                 XmlUtil.writeNextValue(out, XML_TAG_WIFI_SSID,
2135                         softApConfig.getWifiSsid().toString());
2136             }
2137             if (softApConfig.getBssid() != null) {
2138                 XmlUtil.writeNextValue(out, XML_TAG_BSSID, softApConfig.getBssid().toString());
2139             }
2140             if (!SdkLevel.isAtLeastS()) {
2141                 // Band and channel change to store in Tag:BandChannelMap from S.
2142                 XmlUtil.writeNextValue(out, XML_TAG_AP_BAND, softApConfig.getBand());
2143                 XmlUtil.writeNextValue(out, XML_TAG_CHANNEL, softApConfig.getChannel());
2144             }
2145             XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, softApConfig.isHiddenSsid());
2146             XmlUtil.writeNextValue(out, XML_TAG_SECURITY_TYPE, softApConfig.getSecurityType());
2147             if (!ApConfigUtil.isNonPasswordAP(softApConfig.getSecurityType())) {
2148                 XmlUtil.writeSoftApPassphraseToXml(out, softApConfig.getPassphrase(),
2149                         encryptionUtil);
2150             }
2151 
2152             XmlUtil.writeNextValue(out, XML_TAG_MAX_NUMBER_OF_CLIENTS,
2153                     softApConfig.getMaxNumberOfClients());
2154             XmlUtil.writeNextValue(out, XML_TAG_CLIENT_CONTROL_BY_USER,
2155                     softApConfig.isClientControlByUserEnabled());
2156             XmlUtil.writeNextValue(out, XML_TAG_AUTO_SHUTDOWN_ENABLED,
2157                     softApConfig.isAutoShutdownEnabled());
2158             XmlUtil.writeNextValue(out, XML_TAG_SHUTDOWN_TIMEOUT_MILLIS,
2159                     softApConfig.getShutdownTimeoutMillis());
2160             XmlUtil.writeNextSectionStart(out, XML_TAG_BLOCKED_CLIENT_LIST);
2161             XmlUtil.SoftApConfigurationXmlUtil.writeClientListToXml(out,
2162                     softApConfig.getBlockedClientList());
2163             XmlUtil.writeNextSectionEnd(out, XML_TAG_BLOCKED_CLIENT_LIST);
2164 
2165             XmlUtil.writeNextSectionStart(out, XML_TAG_ALLOWED_CLIENT_LIST);
2166             XmlUtil.SoftApConfigurationXmlUtil.writeClientListToXml(out,
2167                     softApConfig.getAllowedClientList());
2168             XmlUtil.writeNextSectionEnd(out, XML_TAG_ALLOWED_CLIENT_LIST);
2169             if (SdkLevel.isAtLeastS()) {
2170                 XmlUtil.writeNextValue(out, XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_ENABLED,
2171                         softApConfig.isBridgedModeOpportunisticShutdownEnabled());
2172                 XmlUtil.writeNextValue(out, XML_TAG_MAC_RAMDOMIZATION_SETTING,
2173                         softApConfig.getMacRandomizationSetting());
2174 
2175                 XmlUtil.writeNextSectionStart(out, XML_TAG_BAND_CHANNEL_MAP);
2176                 XmlUtil.SoftApConfigurationXmlUtil.writeChannelsToXml(out,
2177                         softApConfig.getChannels());
2178                 XmlUtil.writeNextSectionEnd(out, XML_TAG_BAND_CHANNEL_MAP);
2179                 XmlUtil.writeNextValue(out, XML_TAG_80211_AX_ENABLED,
2180                         softApConfig.isIeee80211axEnabled());
2181                 XmlUtil.writeNextValue(out, XML_TAG_USER_CONFIGURATION,
2182                         softApConfig.isUserConfiguration());
2183             }
2184             if (SdkLevel.isAtLeastT()) {
2185                 XmlUtil.writeNextValue(out,
2186                         XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_TIMEOUT_MILLIS,
2187                         softApConfig.getBridgedModeOpportunisticShutdownTimeoutMillisInternal());
2188                 XmlUtil.writeNextSectionStart(out, XML_TAG_VENDOR_ELEMENTS);
2189                 XmlUtil.SoftApConfigurationXmlUtil.writeVendorElementsSetToXml(out,
2190                         softApConfig.getVendorElementsInternal());
2191                 XmlUtil.writeNextSectionEnd(out, XML_TAG_VENDOR_ELEMENTS);
2192                 XmlUtil.writeNextValue(out, XML_TAG_80211_BE_ENABLED,
2193                         softApConfig.isIeee80211beEnabled());
2194                 if (softApConfig.getPersistentRandomizedMacAddress() != null) {
2195                     XmlUtil.writeNextValue(out, XML_TAG_PERSISTENT_RANDOMIZED_MAC_ADDRESS,
2196                             softApConfig.getPersistentRandomizedMacAddress().toString());
2197                 }
2198             }
2199             if (SdkLevel.isAtLeastV()) {
2200                 writeVendorDataListToXml(out, softApConfig.getVendorData());
2201             }
2202         } // End of writeSoftApConfigurationToXml
2203 
2204         /**
2205          * Returns configuration of the SoftAp from the XML stream.
2206          *
2207          * @param in XmlPullParser instance pointing to the XML stream.
2208          * @param outerTagDepth depth of the outer tag in the XML document.
2209          * @param settingsMigrationDataHolder the class instance of SettingsMigrationDataHolder
2210          */
2211         @Nullable
parseFromXml(XmlPullParser in, int outerTagDepth, SettingsMigrationDataHolder settingsMigrationDataHolder, boolean shouldExpectEncryptedCredentials, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)2212         public static SoftApConfiguration parseFromXml(XmlPullParser in, int outerTagDepth,
2213                 SettingsMigrationDataHolder settingsMigrationDataHolder,
2214                 boolean shouldExpectEncryptedCredentials,
2215                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
2216                 throws XmlPullParserException, IOException  {
2217             SoftApConfiguration.Builder softApConfigBuilder = new SoftApConfiguration.Builder();
2218             int securityType = SoftApConfiguration.SECURITY_TYPE_OPEN;
2219             String passphrase = null;
2220             // SSID may be retrieved from the old encoding (XML_TAG_SSID) or the new encoding
2221             // (XML_TAG_WIFI_SSID).
2222             boolean hasSsid = false;
2223             String bssid = null;
2224             // Note that, during deserialization, we may read the old band encoding (XML_TAG_BAND)
2225             // or the new band encoding (XML_TAG_AP_BAND) that is used after the introduction of the
2226             // 6GHz band. If the old encoding is found, a conversion is done.
2227             int channel = -1;
2228             int apBand = -1;
2229             boolean hasBandChannelMap = false;
2230             List<MacAddress> blockedList = new ArrayList<>();
2231             List<MacAddress> allowedList = new ArrayList<>();
2232             boolean autoShutdownEnabledTagPresent = false;
2233             try {
2234                 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
2235                     if (in.getAttributeValue(null, "name") != null) {
2236                         String[] valueName = new String[1];
2237                         Object value = XmlUtil.readCurrentValue(in, valueName);
2238                         if (TextUtils.isEmpty(valueName[0])) {
2239                             throw new XmlPullParserException("Missing value name");
2240                         }
2241                         switch (valueName[0]) {
2242                             case XML_TAG_SSID:
2243                                 hasSsid = true;
2244                                 softApConfigBuilder.setSsid((String) value);
2245                                 break;
2246                             case XML_TAG_WIFI_SSID:
2247                                 hasSsid = true;
2248                                 final WifiSsid wifiSsid = WifiSsid.fromString((String) value);
2249                                 if (SdkLevel.isAtLeastT()) {
2250                                     softApConfigBuilder.setWifiSsid(wifiSsid);
2251                                 } else {
2252                                     // If the SSID is non-UTF-8, then use WifiManager.UNKNOWN_SSID.
2253                                     // This should not happen since non-UTF-8 SSIDs may only be set
2254                                     // with SoftApConfiguration#Builder#setWifiSsid(WifiSsid),
2255                                     // which is only available in T and above.
2256                                     final CharSequence utf8Ssid = wifiSsid.getUtf8Text();
2257                                     softApConfigBuilder.setSsid(utf8Ssid != null
2258                                             ? utf8Ssid.toString() : WifiManager.UNKNOWN_SSID);
2259                                 }
2260                                 break;
2261                             case XML_TAG_BSSID:
2262                                 bssid = (String) value;
2263                                 softApConfigBuilder.setBssid(MacAddress.fromString(bssid));
2264                                 break;
2265                             case XML_TAG_BAND:
2266                                 apBand = ApConfigUtil.convertWifiConfigBandToSoftApConfigBand(
2267                                         (int) value);
2268                                 break;
2269                             case XML_TAG_AP_BAND:
2270                                 apBand = (int) value;
2271                                 break;
2272                             case XML_TAG_CHANNEL:
2273                                 channel = (int) value;
2274                                 break;
2275                             case XML_TAG_HIDDEN_SSID:
2276                                 softApConfigBuilder.setHiddenSsid((boolean) value);
2277                                 break;
2278                             case XML_TAG_SECURITY_TYPE:
2279                                 securityType = (int) value;
2280                                 break;
2281                             case XML_TAG_WPA2_PASSPHRASE:
2282                             case XML_TAG_PASSPHRASE:
2283                                 passphrase = (String) value;
2284                                 break;
2285                             case XML_TAG_MAX_NUMBER_OF_CLIENTS:
2286                                 softApConfigBuilder.setMaxNumberOfClients((int) value);
2287                                 break;
2288                             case XML_TAG_AUTO_SHUTDOWN_ENABLED:
2289                                 softApConfigBuilder.setAutoShutdownEnabled((boolean) value);
2290                                 autoShutdownEnabledTagPresent = true;
2291                                 break;
2292                             case XML_TAG_SHUTDOWN_TIMEOUT_MILLIS:
2293                                 long shutDownMillis = 0;
2294                                 if (value instanceof Integer) {
2295                                     shutDownMillis = Long.valueOf((int) value);
2296                                 } else if (value instanceof Long) {
2297                                     shutDownMillis = (long) value;
2298                                 }
2299                                 if (shutDownMillis == 0
2300                                         && CompatChanges.isChangeEnabled(
2301                                         SoftApConfiguration.REMOVE_ZERO_FOR_TIMEOUT_SETTING)) {
2302                                     shutDownMillis = SoftApConfiguration.DEFAULT_TIMEOUT;
2303                                 }
2304                                 softApConfigBuilder.setShutdownTimeoutMillis(shutDownMillis);
2305                                 break;
2306                             case XML_TAG_CLIENT_CONTROL_BY_USER:
2307                                 softApConfigBuilder.setClientControlByUserEnabled((boolean) value);
2308                                 break;
2309                             case XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_ENABLED:
2310                                 if (SdkLevel.isAtLeastS()) {
2311                                     softApConfigBuilder.setBridgedModeOpportunisticShutdownEnabled(
2312                                             (boolean) value);
2313                                 }
2314                                 break;
2315                             case XML_TAG_MAC_RAMDOMIZATION_SETTING:
2316                                 if (SdkLevel.isAtLeastS()) {
2317                                     softApConfigBuilder.setMacRandomizationSetting((int) value);
2318                                 }
2319                                 break;
2320                             case XML_TAG_80211_AX_ENABLED:
2321                                 if (SdkLevel.isAtLeastS()) {
2322                                     softApConfigBuilder.setIeee80211axEnabled((boolean) value);
2323                                 }
2324                                 break;
2325                             case XML_TAG_80211_BE_ENABLED:
2326                                 if (SdkLevel.isAtLeastT()) {
2327                                     softApConfigBuilder.setIeee80211beEnabled((boolean) value);
2328                                 }
2329                                 break;
2330                             case XML_TAG_USER_CONFIGURATION:
2331                                 if (SdkLevel.isAtLeastS()) {
2332                                     softApConfigBuilder.setUserConfiguration((boolean) value);
2333                                 }
2334                                 break;
2335                             case XML_TAG_BRIDGED_MODE_OPPORTUNISTIC_SHUTDOWN_TIMEOUT_MILLIS:
2336                                 if (SdkLevel.isAtLeastT()) {
2337                                     long bridgedTimeout = (long) value;
2338                                     bridgedTimeout = bridgedTimeout == 0
2339                                             ? SoftApConfiguration.DEFAULT_TIMEOUT : bridgedTimeout;
2340                                     softApConfigBuilder
2341                                             .setBridgedModeOpportunisticShutdownTimeoutMillis(
2342                                                     bridgedTimeout);
2343                                 }
2344                                 break;
2345                             case XML_TAG_PERSISTENT_RANDOMIZED_MAC_ADDRESS:
2346                                 if (SdkLevel.isAtLeastT()) {
2347                                     softApConfigBuilder.setRandomizedMacAddress(
2348                                             MacAddress.fromString((String) value));
2349                                 }
2350                                 break;
2351                             default:
2352                                 Log.w(TAG, "Ignoring unknown value name " + valueName[0]);
2353                                 break;
2354                         }
2355                     } else {
2356                         String tagName = in.getName();
2357                         List<MacAddress> parseredList;
2358                         if (tagName == null) {
2359                             throw new XmlPullParserException("Unexpected null tag found");
2360                         }
2361                         switch (tagName) {
2362                             case XML_TAG_BLOCKED_CLIENT_LIST:
2363                                 parseredList =
2364                                         XmlUtil.SoftApConfigurationXmlUtil.parseClientListFromXml(
2365                                         in, outerTagDepth + 1);
2366                                 if (parseredList != null) {
2367                                     blockedList = new ArrayList<>(parseredList);
2368                                 }
2369                                 break;
2370                             case XML_TAG_ALLOWED_CLIENT_LIST:
2371                                 parseredList =
2372                                         XmlUtil.SoftApConfigurationXmlUtil.parseClientListFromXml(
2373                                         in, outerTagDepth + 1);
2374                                 if (parseredList != null) {
2375                                     allowedList = new ArrayList<>(parseredList);
2376                                 }
2377                                 break;
2378                             case XML_TAG_BAND_CHANNEL_MAP:
2379                                 if (SdkLevel.isAtLeastS()) {
2380                                     hasBandChannelMap = true;
2381                                     SparseIntArray channels = XmlUtil.SoftApConfigurationXmlUtil
2382                                             .parseChannelsFromXml(in, outerTagDepth + 1);
2383                                     softApConfigBuilder.setChannels(channels);
2384                                 }
2385                                 break;
2386                             case XML_TAG_VENDOR_ELEMENTS:
2387                                 if (SdkLevel.isAtLeastT()) {
2388                                     softApConfigBuilder.setVendorElements(
2389                                             SoftApConfigurationXmlUtil.parseVendorElementsFromXml(
2390                                                     in, outerTagDepth + 1));
2391                                 }
2392                                 break;
2393                             case XML_TAG_PASSPHRASE:
2394                                 passphrase = readSoftApPassphraseFromXml(in, outerTagDepth,
2395                                         shouldExpectEncryptedCredentials, encryptionUtil);
2396                                 break;
2397                             case XML_TAG_VENDOR_DATA_LIST:
2398                                 if (SdkLevel.isAtLeastV()) {
2399                                     softApConfigBuilder.setVendorData(
2400                                             parseVendorDataListFromXml(in, outerTagDepth + 1));
2401                                 }
2402                                 break;
2403                             default:
2404                                 Log.w(TAG, "Ignoring unknown tag found: " + tagName);
2405                                 break;
2406                         }
2407                     }
2408                 }
2409                 softApConfigBuilder.setBlockedClientList(blockedList);
2410                 softApConfigBuilder.setAllowedClientList(allowedList);
2411                 if (!hasBandChannelMap) {
2412                     // Set channel and band
2413                     if (channel == 0) {
2414                         softApConfigBuilder.setBand(apBand);
2415                     } else {
2416                         softApConfigBuilder.setChannel(channel, apBand);
2417                     }
2418                 }
2419 
2420                 // We should at least have an SSID restored from store.
2421                 if (!hasSsid) {
2422                     Log.e(TAG, "Failed to parse SSID");
2423                     return null;
2424                 }
2425                 if (ApConfigUtil.isNonPasswordAP(securityType)) {
2426                     softApConfigBuilder.setPassphrase(null, securityType);
2427                 } else {
2428                     softApConfigBuilder.setPassphrase(passphrase, securityType);
2429                 }
2430                 if (!autoShutdownEnabledTagPresent) {
2431                     // Migrate data out of settings.
2432                     WifiMigration.SettingsMigrationData migrationData =
2433                             settingsMigrationDataHolder.retrieveData();
2434                     if (migrationData == null) {
2435                         Log.e(TAG, "No migration data present");
2436                     } else {
2437                         softApConfigBuilder.setAutoShutdownEnabled(
2438                                 migrationData.isSoftApTimeoutEnabled());
2439                     }
2440                 }
2441                 if (bssid != null && SdkLevel.isAtLeastS()) {
2442                     // Force MAC randomization setting to none when BSSID is configured
2443                     softApConfigBuilder.setMacRandomizationSetting(
2444                             SoftApConfiguration.RANDOMIZATION_NONE);
2445                 }
2446             } catch (IllegalArgumentException e) {
2447                 Log.e(TAG, "Failed to parse configuration " + e);
2448                 return null;
2449             }
2450             return softApConfigBuilder.build();
2451         } // End of parseFromXml
2452     }
2453 
writeSoftApPassphraseToXml( XmlSerializer out, String passphrase, WifiConfigStoreEncryptionUtil encryptionUtil)2454     private static void writeSoftApPassphraseToXml(
2455             XmlSerializer out, String passphrase, WifiConfigStoreEncryptionUtil encryptionUtil)
2456             throws XmlPullParserException, IOException {
2457         EncryptedData encryptedData = null;
2458         if (encryptionUtil != null && passphrase != null) {
2459             encryptedData = encryptionUtil.encrypt(passphrase.getBytes());
2460             if (encryptedData == null) {
2461                 // We silently fail encryption failures!
2462                 Log.wtf(TAG, "Encryption of softAp passphrase failed");
2463             }
2464         }
2465         if (encryptedData != null) {
2466             writeNextSectionStart(out, SoftApConfigurationXmlUtil.XML_TAG_PASSPHRASE);
2467             EncryptedDataXmlUtil.writeToXml(out, encryptedData);
2468             writeNextSectionEnd(out, SoftApConfigurationXmlUtil.XML_TAG_PASSPHRASE);
2469         } else {
2470             writeNextValue(out, SoftApConfigurationXmlUtil.XML_TAG_PASSPHRASE, passphrase);
2471         }
2472     }
2473 
readSoftApPassphraseFromXml(XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, WifiConfigStoreEncryptionUtil encryptionUtil)2474     private static String readSoftApPassphraseFromXml(XmlPullParser in, int outerTagDepth,
2475             boolean shouldExpectEncryptedCredentials, WifiConfigStoreEncryptionUtil encryptionUtil)
2476             throws XmlPullParserException, IOException {
2477         if (!shouldExpectEncryptedCredentials || encryptionUtil == null) {
2478             throw new XmlPullParserException(
2479                     "Encrypted passphraseBytes section not expected");
2480         }
2481         EncryptedData encryptedData =
2482                 XmlUtil.EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1);
2483         byte[] passphraseBytes = encryptionUtil.decrypt(encryptedData);
2484         if (passphraseBytes == null) {
2485             Log.wtf(TAG, "Decryption of passphraseBytes failed");
2486             return null;
2487         } else {
2488             return new String(passphraseBytes);
2489         }
2490     }
2491 
2492     /**
2493      * Write the provided vendor data list to XML.
2494      *
2495      * @param out XmlSerializer instance pointing to the XML stream
2496      * @param vendorDataList Vendor data list
2497      */
writeVendorDataListToXml( XmlSerializer out, List<OuiKeyedData> vendorDataList)2498     private static void writeVendorDataListToXml(
2499             XmlSerializer out, List<OuiKeyedData> vendorDataList)
2500             throws XmlPullParserException, IOException {
2501         if (vendorDataList == null || vendorDataList.isEmpty()) {
2502             return;
2503         }
2504         XmlUtil.writeNextSectionStart(out, XML_TAG_VENDOR_DATA_LIST);
2505         for (OuiKeyedData data : vendorDataList) {
2506             writeOuiKeyedDataToXml(out, data);
2507         }
2508         XmlUtil.writeNextSectionEnd(out, XML_TAG_VENDOR_DATA_LIST);
2509     }
2510 
writeOuiKeyedDataToXml( XmlSerializer out, OuiKeyedData ouiKeyedData)2511     private static void writeOuiKeyedDataToXml(
2512             XmlSerializer out, OuiKeyedData ouiKeyedData)
2513             throws XmlPullParserException, IOException {
2514         // PersistableBundle cannot be written directly to XML
2515         // Use byte[] as an intermediate data structure
2516         if (ouiKeyedData == null) return;
2517         byte[] bundleBytes;
2518         try {
2519             ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
2520             ouiKeyedData.getData().writeToStream(outputStream);
2521             bundleBytes = outputStream.toByteArray();
2522         } catch (Exception e) {
2523             Log.e(TAG, "Unable to write PersistableBundle to byte[]");
2524             return;
2525         }
2526         XmlUtil.writeNextSectionStart(out, XML_TAG_OUI_KEYED_DATA);
2527         XmlUtil.writeNextValue(out, XML_TAG_VENDOR_DATA_OUI, ouiKeyedData.getOui());
2528         XmlUtil.writeNextValue(out, XML_TAG_PERSISTABLE_BUNDLE, bundleBytes);
2529         XmlUtil.writeNextSectionEnd(out, XML_TAG_OUI_KEYED_DATA);
2530     }
2531 
2532     /**
2533      * Parses the vendor data list from the provided XML stream .
2534      *
2535      * @param in XmlPullParser instance pointing to the XML stream
2536      * @param outerTagDepth depth of the outer tag in the XML document
2537      * @return List of OuiKeyedData if successful, empty list otherwise
2538      */
parseVendorDataListFromXml( XmlPullParser in, int outerTagDepth)2539     private static List<OuiKeyedData> parseVendorDataListFromXml(
2540             XmlPullParser in, int outerTagDepth)
2541             throws XmlPullParserException, IOException, IllegalArgumentException {
2542         List<OuiKeyedData> vendorDataList = new ArrayList<>();
2543         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
2544             String tagName = in.getName();
2545             if (tagName == null) {
2546                 throw new XmlPullParserException("Unexpected null tag found");
2547             }
2548             switch (tagName) {
2549                 case XML_TAG_OUI_KEYED_DATA:
2550                     OuiKeyedData data = parseOuiKeyedDataFromXml(in, outerTagDepth + 1);
2551                     if (data != null) {
2552                         vendorDataList.add(data);
2553                     }
2554                     break;
2555                 default:
2556                     Log.w(TAG, "Ignoring unknown tag found: " + tagName);
2557                     break;
2558             }
2559         }
2560         return vendorDataList;
2561     }
2562 
readPersistableBundleFromBytes(byte[] bundleBytes)2563     private static PersistableBundle readPersistableBundleFromBytes(byte[] bundleBytes) {
2564         try {
2565             ByteArrayInputStream inputStream = new ByteArrayInputStream(bundleBytes);
2566             return PersistableBundle.readFromStream(inputStream);
2567         } catch (Exception e) {
2568             Log.e(TAG, "Unable to read PersistableBundle from byte[]");
2569             return null;
2570         }
2571     }
2572 
parseOuiKeyedDataFromXml( XmlPullParser in, int outerTagDepth)2573     private static OuiKeyedData parseOuiKeyedDataFromXml(
2574             XmlPullParser in, int outerTagDepth)
2575             throws XmlPullParserException, IOException, IllegalArgumentException {
2576         int oui = 0;
2577         PersistableBundle bundle = null;
2578 
2579         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
2580             String[] valueName = new String[1];
2581             Object value = XmlUtil.readCurrentValue(in, valueName);
2582             if (valueName[0] == null) {
2583                 throw new XmlPullParserException("Missing value name");
2584             }
2585             switch (valueName[0]) {
2586                 case XML_TAG_VENDOR_DATA_OUI:
2587                     oui = (int) value;
2588                     break;
2589                 case XML_TAG_PERSISTABLE_BUNDLE:
2590                     bundle = readPersistableBundleFromBytes((byte[]) value);
2591                     break;
2592                 default:
2593                     Log.e(TAG, "Unknown value name found: " + valueName[0]);
2594                     break;
2595             }
2596         }
2597 
2598         try {
2599             return new OuiKeyedData.Builder(oui, bundle).build();
2600         } catch (Exception e) {
2601             Log.e(TAG, "Unable to build OuiKeyedData");
2602             return null;
2603         }
2604     }
2605 }
2606