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