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