• 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.net.InetAddresses;
22 import android.net.IpConfiguration;
23 import android.net.IpConfiguration.IpAssignment;
24 import android.net.IpConfiguration.ProxySettings;
25 import android.net.LinkAddress;
26 import android.net.MacAddress;
27 import android.net.ProxyInfo;
28 import android.net.RouteInfo;
29 import android.net.StaticIpConfiguration;
30 import android.net.Uri;
31 import android.net.wifi.SecurityParams;
32 import android.net.wifi.WifiConfiguration;
33 import android.net.wifi.WifiConfiguration.NetworkSelectionStatus;
34 import android.net.wifi.WifiEnterpriseConfig;
35 import android.text.TextUtils;
36 import android.util.Log;
37 import android.util.Pair;
38 import android.util.SparseIntArray;
39 
40 import com.android.modules.utils.build.SdkLevel;
41 
42 import org.xmlpull.v1.XmlPullParser;
43 import org.xmlpull.v1.XmlPullParserException;
44 import org.xmlpull.v1.XmlSerializer;
45 
46 import java.io.IOException;
47 import java.net.Inet4Address;
48 import java.net.InetAddress;
49 import java.util.ArrayList;
50 import java.util.Arrays;
51 import java.util.BitSet;
52 import java.util.Collections;
53 import java.util.HashMap;
54 import java.util.List;
55 import java.util.Locale;
56 
57 /**
58  * Utils for manipulating XML data. This is essentially a wrapper over XmlUtils provided by core.
59  * The utility provides methods to write/parse section headers and write/parse values.
60  * This utility is designed for formatting the XML into the following format:
61  * <Document Header>
62  *  <Section 1 Header>
63  *   <Value 1>
64  *   <Value 2>
65  *   ...
66  *   <Sub Section 1 Header>
67  *    <Value 1>
68  *    <Value 2>
69  *    ...
70  *   </Sub Section 1 Header>
71  *  </Section 1 Header>
72  * </Document Header>
73  *
74  * Note: These utility methods are meant to be used for:
75  * 1. Backup/restore wifi network data to/from cloud.
76  * 2. Persisting wifi network data to/from disk.
77  */
78 public class XmlUtil {
79     private static final String TAG = "WifiXmlUtil";
80 
81     /**
82      * Ensure that the XML stream is at a start tag or the end of document.
83      *
84      * @throws XmlPullParserException if parsing errors occur.
85      */
gotoStartTag(XmlPullParser in)86     private static void gotoStartTag(XmlPullParser in)
87             throws XmlPullParserException, IOException {
88         int type = in.getEventType();
89         while (type != XmlPullParser.START_TAG && type != XmlPullParser.END_DOCUMENT) {
90             type = in.next();
91         }
92     }
93 
94     /**
95      * Ensure that the XML stream is at an end tag or the end of document.
96      *
97      * @throws XmlPullParserException if parsing errors occur.
98      */
gotoEndTag(XmlPullParser in)99     private static void gotoEndTag(XmlPullParser in)
100             throws XmlPullParserException, IOException {
101         int type = in.getEventType();
102         while (type != XmlPullParser.END_TAG && type != XmlPullParser.END_DOCUMENT) {
103             type = in.next();
104         }
105     }
106 
107     /**
108      * Start processing the XML stream at the document header.
109      *
110      * @param in         XmlPullParser instance pointing to the XML stream.
111      * @param headerName expected name for the start tag.
112      * @throws XmlPullParserException if parsing errors occur.
113      */
gotoDocumentStart(XmlPullParser in, String headerName)114     public static void gotoDocumentStart(XmlPullParser in, String headerName)
115             throws XmlPullParserException, IOException {
116         XmlUtilHelper.beginDocument(in, headerName);
117     }
118 
119     /**
120      * Move the XML stream to the next section header or indicate if there are no more sections.
121      * The provided outerDepth is used to find sub sections within that depth.
122      *
123      * Use this to move across sections if the ordering of sections are variable. The returned name
124      * can be used to decide what section is next.
125      *
126      * @param in         XmlPullParser instance pointing to the XML stream.
127      * @param headerName An array of one string, used to return the name of the next section.
128      * @param outerDepth Find section within this depth.
129      * @return {@code true} if a next section is found, {@code false} if there are no more sections.
130      * @throws XmlPullParserException if parsing errors occur.
131      */
gotoNextSectionOrEnd( XmlPullParser in, String[] headerName, int outerDepth)132     public static boolean gotoNextSectionOrEnd(
133             XmlPullParser in, String[] headerName, int outerDepth)
134             throws XmlPullParserException, IOException {
135         if (XmlUtilHelper.nextElementWithin(in, outerDepth)) {
136             headerName[0] = in.getName();
137             return true;
138         }
139         return false;
140     }
141 
142     /**
143      * Move the XML stream to the next section header or indicate if there are no more sections.
144      * If a section, exists ensure that the name matches the provided name.
145      * The provided outerDepth is used to find sub sections within that depth.
146      *
147      * Use this to move across repeated sections until the end.
148      *
149      * @param in           XmlPullParser instance pointing to the XML stream.
150      * @param expectedName expected name for the section header.
151      * @param outerDepth   Find section within this depth.
152      * @return {@code true} if a next section is found, {@code false} if there are no more sections.
153      * @throws XmlPullParserException if the section header name does not match |expectedName|,
154      *                                or if parsing errors occur.
155      */
gotoNextSectionWithNameOrEnd( XmlPullParser in, String expectedName, int outerDepth)156     public static boolean gotoNextSectionWithNameOrEnd(
157             XmlPullParser in, String expectedName, int outerDepth)
158             throws XmlPullParserException, IOException {
159         String[] headerName = new String[1];
160         if (gotoNextSectionOrEnd(in, headerName, outerDepth)) {
161             if (headerName[0].equals(expectedName)) {
162                 return true;
163             }
164             throw new XmlPullParserException(
165                     "Next section name does not match expected name: " + expectedName);
166         }
167         return false;
168     }
169 
170     /**
171      * Move the XML stream to the next section header and ensure that the name matches the provided
172      * name.
173      * The provided outerDepth is used to find sub sections within that depth.
174      *
175      * Use this to move across sections if the ordering of sections are fixed.
176      *
177      * @param in           XmlPullParser instance pointing to the XML stream.
178      * @param expectedName expected name for the section header.
179      * @param outerDepth   Find section within this depth.
180      * @throws XmlPullParserException if the section header name does not match |expectedName|,
181      *                                there are no more sections or if parsing errors occur.
182      */
gotoNextSectionWithName( XmlPullParser in, String expectedName, int outerDepth)183     public static void gotoNextSectionWithName(
184             XmlPullParser in, String expectedName, int outerDepth)
185             throws XmlPullParserException, IOException {
186         if (!gotoNextSectionWithNameOrEnd(in, expectedName, outerDepth)) {
187             throw new XmlPullParserException("Section not found. Expected: " + expectedName);
188         }
189     }
190 
191     /**
192      * Checks if the stream is at the end of a section of values. This moves the stream to next tag
193      * and checks if it finds an end tag at the specified depth.
194      *
195      * @param in           XmlPullParser instance pointing to the XML stream.
196      * @param sectionDepth depth of the start tag of this section. Used to match the end tag.
197      * @return {@code true} if a end tag at the provided depth is found, {@code false} otherwise
198      * @throws XmlPullParserException if parsing errors occur.
199      */
isNextSectionEnd(XmlPullParser in, int sectionDepth)200     public static boolean isNextSectionEnd(XmlPullParser in, int sectionDepth)
201             throws XmlPullParserException, IOException {
202         return !XmlUtilHelper.nextElementWithin(in, sectionDepth);
203     }
204 
205     /**
206      * Read the current value in the XML stream using core XmlUtils and stores the retrieved
207      * value name in the string provided. This method reads the value contained in current start
208      * tag.
209      * Note: Because there could be genuine null values being read from the XML, this method raises
210      * an exception to indicate errors.
211      *
212      * @param in        XmlPullParser instance pointing to the XML stream.
213      * @param valueName An array of one string, used to return the name attribute
214      *                  of the value's tag.
215      * @return value retrieved from the XML stream.
216      * @throws XmlPullParserException if parsing errors occur.
217      */
readCurrentValue(XmlPullParser in, String[] valueName)218     public static Object readCurrentValue(XmlPullParser in, String[] valueName)
219             throws XmlPullParserException, IOException {
220         Object value = XmlUtilHelper.readValueXml(in, valueName);
221         // XmlUtils.readValue does not always move the stream to the end of the tag. So, move
222         // it to the end tag before returning from here.
223         gotoEndTag(in);
224         return value;
225     }
226 
227     /**
228      * Read the next value in the XML stream using core XmlUtils and ensure that it matches the
229      * provided name. This method moves the stream to the next start tag and reads the value
230      * contained in it.
231      * Note: Because there could be genuine null values being read from the XML, this method raises
232      * an exception to indicate errors.
233      *
234      * @param in XmlPullParser instance pointing to the XML stream.
235      * @return value retrieved from the XML stream.
236      * @throws XmlPullParserException if the value read does not match |expectedName|,
237      *                                or if parsing errors occur.
238      */
readNextValueWithName(XmlPullParser in, String expectedName)239     public static Object readNextValueWithName(XmlPullParser in, String expectedName)
240             throws XmlPullParserException, IOException {
241         String[] valueName = new String[1];
242         XmlUtilHelper.nextElement(in);
243         Object value = readCurrentValue(in, valueName);
244         if (valueName[0].equals(expectedName)) {
245             return value;
246         }
247         throw new XmlPullParserException(
248                 "Value not found. Expected: " + expectedName + ", but got: " + valueName[0]);
249     }
250 
251     /**
252      * Write the XML document start with the provided document header name.
253      *
254      * @param out        XmlSerializer instance pointing to the XML stream.
255      * @param headerName name for the start tag.
256      */
writeDocumentStart(XmlSerializer out, String headerName)257     public static void writeDocumentStart(XmlSerializer out, String headerName)
258             throws IOException {
259         out.startDocument(null, true);
260         out.startTag(null, headerName);
261     }
262 
263     /**
264      * Write the XML document end with the provided document header name.
265      *
266      * @param out        XmlSerializer instance pointing to the XML stream.
267      * @param headerName name for the end tag.
268      */
writeDocumentEnd(XmlSerializer out, String headerName)269     public static void writeDocumentEnd(XmlSerializer out, String headerName)
270             throws IOException {
271         out.endTag(null, headerName);
272         out.endDocument();
273     }
274 
275     /**
276      * Write a section start header tag with the provided section name.
277      *
278      * @param out        XmlSerializer instance pointing to the XML stream.
279      * @param headerName name for the start tag.
280      */
writeNextSectionStart(XmlSerializer out, String headerName)281     public static void writeNextSectionStart(XmlSerializer out, String headerName)
282             throws IOException {
283         out.startTag(null, headerName);
284     }
285 
286     /**
287      * Write a section end header tag with the provided section name.
288      *
289      * @param out        XmlSerializer instance pointing to the XML stream.
290      * @param headerName name for the end tag.
291      */
writeNextSectionEnd(XmlSerializer out, String headerName)292     public static void writeNextSectionEnd(XmlSerializer out, String headerName)
293             throws IOException {
294         out.endTag(null, headerName);
295     }
296 
297     /**
298      * Write the value with the provided name in the XML stream using core XmlUtils.
299      *
300      * @param out   XmlSerializer instance pointing to the XML stream.
301      * @param name  name of the value.
302      * @param value value to be written.
303      */
writeNextValue(XmlSerializer out, String name, Object value)304     public static void writeNextValue(XmlSerializer out, String name, Object value)
305             throws XmlPullParserException, IOException {
306         XmlUtilHelper.writeValueXml(value, name, out);
307     }
308 
309     /**
310      * Utility class to serialize and deserialize {@link WifiConfiguration} object to XML &
311      * vice versa.
312      * This is used by both {@link com.android.server.wifi.WifiConfigStore} &
313      * {@link com.android.server.wifi.WifiBackupRestore} modules.
314      * The |writeConfigurationToXml| has 2 versions, one for backup and one for config store.
315      * There is only 1 version of |parseXmlToConfiguration| for both backup & config store.
316      * The parse method is written so that any element added/deleted in future revisions can
317      * be easily handled.
318      */
319     public static class WifiConfigurationXmlUtil {
320         /**
321          * List of XML tags corresponding to WifiConfiguration object elements.
322          */
323         public static final String XML_TAG_SSID = "SSID";
324         public static final String XML_TAG_BSSID = "BSSID";
325         public static final String XML_TAG_CONFIG_KEY = "ConfigKey";
326         public static final String XML_TAG_PRE_SHARED_KEY = "PreSharedKey";
327         public static final String XML_TAG_WEP_KEYS = "WEPKeys";
328         public static final String XML_TAG_WEP_TX_KEY_INDEX = "WEPTxKeyIndex";
329         public static final String XML_TAG_HIDDEN_SSID = "HiddenSSID";
330         public static final String XML_TAG_REQUIRE_PMF = "RequirePMF";
331         public static final String XML_TAG_ALLOWED_KEY_MGMT = "AllowedKeyMgmt";
332         public static final String XML_TAG_ALLOWED_PROTOCOLS = "AllowedProtocols";
333         public static final String XML_TAG_ALLOWED_AUTH_ALGOS = "AllowedAuthAlgos";
334         public static final String XML_TAG_ALLOWED_GROUP_CIPHERS = "AllowedGroupCiphers";
335         public static final String XML_TAG_ALLOWED_PAIRWISE_CIPHERS = "AllowedPairwiseCiphers";
336         public static final String XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS = "AllowedGroupMgmtCiphers";
337         public static final String XML_TAG_ALLOWED_SUITE_B_CIPHERS = "AllowedSuiteBCiphers";
338         public static final String XML_TAG_SHARED = "Shared";
339         public static final String XML_TAG_STATUS = "Status";
340         public static final String XML_TAG_FQDN = "FQDN";
341         public static final String XML_TAG_PROVIDER_FRIENDLY_NAME = "ProviderFriendlyName";
342         public static final String XML_TAG_LINKED_NETWORKS_LIST = "LinkedNetworksList";
343         public static final String XML_TAG_DEFAULT_GW_MAC_ADDRESS = "DefaultGwMacAddress";
344         public static final String XML_TAG_VALIDATED_INTERNET_ACCESS = "ValidatedInternetAccess";
345         public static final String XML_TAG_NO_INTERNET_ACCESS_EXPECTED = "NoInternetAccessExpected";
346         public static final String XML_TAG_METERED_HINT = "MeteredHint";
347         public static final String XML_TAG_METERED_OVERRIDE = "MeteredOverride";
348         public static final String XML_TAG_USE_EXTERNAL_SCORES = "UseExternalScores";
349         public static final String XML_TAG_CREATOR_UID = "CreatorUid";
350         public static final String XML_TAG_CREATOR_NAME = "CreatorName";
351         public static final String XML_TAG_LAST_UPDATE_UID = "LastUpdateUid";
352         public static final String XML_TAG_LAST_UPDATE_NAME = "LastUpdateName";
353         public static final String XML_TAG_LAST_CONNECT_UID = "LastConnectUid";
354         public static final String XML_TAG_IS_LEGACY_PASSPOINT_CONFIG = "IsLegacyPasspointConfig";
355         public static final String XML_TAG_ROAMING_CONSORTIUM_OIS = "RoamingConsortiumOIs";
356         public static final String XML_TAG_RANDOMIZED_MAC_ADDRESS = "RandomizedMacAddress";
357         public static final String XML_TAG_MAC_RANDOMIZATION_SETTING = "MacRandomizationSetting";
358         public static final String XML_TAG_CARRIER_ID = "CarrierId";
359         public static final String XML_TAG_SUBSCRIPTION_ID = "SubscriptionId";
360         public static final String XML_TAG_IS_AUTO_JOIN = "AutoJoinEnabled";
361         public static final String XML_TAG_DELETION_PRIORITY = "DeletionPriority";
362         public static final String XML_TAG_NUM_REBOOTS_SINCE_LAST_USE = "NumRebootsSinceLastUse";
363 
364         public static final String XML_TAG_IS_TRUSTED = "Trusted";
365         public static final String XML_TAG_IS_OEM_PAID = "OemPaid";
366         public static final String XML_TAG_IS_OEM_PRIVATE = "OemPrivate";
367         public static final String XML_TAG_IS_CARRIER_MERGED = "CarrierMerged";
368         public static final String XML_TAG_SECURITY_PARAMS_LIST = "SecurityParamsList";
369         public static final String XML_TAG_SECURITY_PARAMS = "SecurityParams";
370         public static final String XML_TAG_SECURITY_TYPE = "SecurityType";
371         public static final String XML_TAG_SAE_IS_H2E_ONLY_MODE = "SaeIsH2eOnlyMode";
372         public static final String XML_TAG_SAE_IS_PK_ONLY_MODE = "SaeIsPkOnlyMode";
373         public static final String XML_TAG_IS_ADDED_BY_AUTO_UPGRADE = "IsAddedByAutoUpgrade";
374         private static final String XML_TAG_IS_MOST_RECENTLY_CONNECTED = "IsMostRecentlyConnected";
375 
376         /**
377          * Write WepKeys to the XML stream.
378          * WepKeys array is intialized in WifiConfiguration constructor, but all of the elements
379          * are set to null. User may chose to set any one of the key elements in WifiConfiguration.
380          * XmlUtils serialization doesn't handle this array of nulls well .
381          * So, write empty strings if some of the keys are not initialized and null if all of
382          * the elements are empty.
383          */
writeWepKeysToXml(XmlSerializer out, String[] wepKeys)384         private static void writeWepKeysToXml(XmlSerializer out, String[] wepKeys)
385                 throws XmlPullParserException, IOException {
386             String[] wepKeysToWrite = new String[wepKeys.length];
387             boolean hasWepKey = false;
388             for (int i = 0; i < wepKeys.length; i++) {
389                 if (wepKeys[i] == null) {
390                     wepKeysToWrite[i] = new String();
391                 } else {
392                     wepKeysToWrite[i] = wepKeys[i];
393                     hasWepKey = true;
394                 }
395             }
396             if (hasWepKey) {
397                 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, wepKeysToWrite);
398             } else {
399                 XmlUtil.writeNextValue(out, XML_TAG_WEP_KEYS, null);
400             }
401         }
402 
403         /**
404          * Write preshared key to the XML stream.
405          *
406          * If encryptionUtil is null or if encryption fails for some reason, the pre-shared
407          * key is stored in plaintext, else the encrypted psk is stored.
408          */
writePreSharedKeyToXml( XmlSerializer out, String preSharedKey, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)409         private static void writePreSharedKeyToXml(
410                 XmlSerializer out, String preSharedKey,
411                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
412                 throws XmlPullParserException, IOException {
413             EncryptedData encryptedData = null;
414             if (encryptionUtil != null) {
415                 if (preSharedKey != null) {
416                     encryptedData = encryptionUtil.encrypt(preSharedKey.getBytes());
417                     if (encryptedData == null) {
418                         // We silently fail encryption failures!
419                         Log.wtf(TAG, "Encryption of preSharedKey failed");
420                     }
421                 }
422             }
423             if (encryptedData != null) {
424                 XmlUtil.writeNextSectionStart(out, XML_TAG_PRE_SHARED_KEY);
425                 EncryptedDataXmlUtil.writeToXml(out, encryptedData);
426                 XmlUtil.writeNextSectionEnd(out, XML_TAG_PRE_SHARED_KEY);
427             } else {
428                 XmlUtil.writeNextValue(out, XML_TAG_PRE_SHARED_KEY, preSharedKey);
429             }
430         }
431 
writeSecurityParamsListToXml( XmlSerializer out, WifiConfiguration configuration)432         private static void writeSecurityParamsListToXml(
433                 XmlSerializer out, WifiConfiguration configuration)
434                 throws XmlPullParserException, IOException {
435             XmlUtil.writeNextSectionStart(out, XML_TAG_SECURITY_PARAMS_LIST);
436             for (SecurityParams params: configuration.getSecurityParamsList()) {
437                 XmlUtil.writeNextSectionStart(out, XML_TAG_SECURITY_PARAMS);
438                 XmlUtil.writeNextValue(
439                         out, XML_TAG_SECURITY_TYPE,
440                         params.getSecurityType());
441                 XmlUtil.writeNextValue(
442                         out, XML_TAG_SAE_IS_H2E_ONLY_MODE,
443                         params.isSaeH2eOnlyMode());
444                 XmlUtil.writeNextValue(
445                         out, XML_TAG_SAE_IS_PK_ONLY_MODE,
446                         params.isSaePkOnlyMode());
447                 XmlUtil.writeNextValue(
448                         out, XML_TAG_IS_ADDED_BY_AUTO_UPGRADE,
449                         params.isAddedByAutoUpgrade());
450                 XmlUtil.writeNextSectionEnd(out, XML_TAG_SECURITY_PARAMS);
451             }
452 
453             XmlUtil.writeNextSectionEnd(out, XML_TAG_SECURITY_PARAMS_LIST);
454         }
455 
456         /**
457          * Write the Configuration data elements that are common for backup & config store to the
458          * XML stream.
459          *
460          * @param out XmlSerializer instance pointing to the XML stream.
461          * @param configuration WifiConfiguration object to be serialized.
462          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}. Backup/restore stores
463          *                       keys unencrypted.
464          */
writeCommonElementsToXml( XmlSerializer out, WifiConfiguration configuration, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)465         public static void writeCommonElementsToXml(
466                 XmlSerializer out, WifiConfiguration configuration,
467                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
468                 throws XmlPullParserException, IOException {
469             XmlUtil.writeNextValue(out, XML_TAG_CONFIG_KEY, configuration.getKey());
470             XmlUtil.writeNextValue(out, XML_TAG_SSID, configuration.SSID);
471             writePreSharedKeyToXml(out, configuration.preSharedKey, encryptionUtil);
472             writeWepKeysToXml(out, configuration.wepKeys);
473             XmlUtil.writeNextValue(out, XML_TAG_WEP_TX_KEY_INDEX, configuration.wepTxKeyIndex);
474             XmlUtil.writeNextValue(out, XML_TAG_HIDDEN_SSID, configuration.hiddenSSID);
475             XmlUtil.writeNextValue(out, XML_TAG_REQUIRE_PMF, configuration.requirePmf);
476             XmlUtil.writeNextValue(
477                     out, XML_TAG_ALLOWED_KEY_MGMT,
478                     configuration.allowedKeyManagement.toByteArray());
479             XmlUtil.writeNextValue(
480                     out, XML_TAG_ALLOWED_PROTOCOLS,
481                     configuration.allowedProtocols.toByteArray());
482             XmlUtil.writeNextValue(
483                     out, XML_TAG_ALLOWED_AUTH_ALGOS,
484                     configuration.allowedAuthAlgorithms.toByteArray());
485             XmlUtil.writeNextValue(
486                     out, XML_TAG_ALLOWED_GROUP_CIPHERS,
487                     configuration.allowedGroupCiphers.toByteArray());
488             XmlUtil.writeNextValue(
489                     out, XML_TAG_ALLOWED_PAIRWISE_CIPHERS,
490                     configuration.allowedPairwiseCiphers.toByteArray());
491             XmlUtil.writeNextValue(
492                     out, XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS,
493                     configuration.allowedGroupManagementCiphers.toByteArray());
494             XmlUtil.writeNextValue(
495                     out, XML_TAG_ALLOWED_SUITE_B_CIPHERS,
496                     configuration.allowedSuiteBCiphers.toByteArray());
497             XmlUtil.writeNextValue(out, XML_TAG_SHARED, configuration.shared);
498             XmlUtil.writeNextValue(out, XML_TAG_IS_AUTO_JOIN, configuration.allowAutojoin);
499             XmlUtil.writeNextValue(
500                     out, XML_TAG_DELETION_PRIORITY,
501                     configuration.getDeletionPriority());
502             XmlUtil.writeNextValue(
503                     out, XML_TAG_NUM_REBOOTS_SINCE_LAST_USE,
504                     configuration.numRebootsSinceLastUse);
505             writeSecurityParamsListToXml(out, configuration);
506         }
507 
508         /**
509          * Write the Configuration data elements for backup from the provided Configuration to the
510          * XML stream.
511          * Note: This is a subset of the elements serialized for config store.
512          *
513          * @param out           XmlSerializer instance pointing to the XML stream.
514          * @param configuration WifiConfiguration object to be serialized.
515          */
writeToXmlForBackup(XmlSerializer out, WifiConfiguration configuration)516         public static void writeToXmlForBackup(XmlSerializer out, WifiConfiguration configuration)
517                 throws XmlPullParserException, IOException {
518             writeCommonElementsToXml(out, configuration, null);
519             XmlUtil.writeNextValue(out, XML_TAG_METERED_OVERRIDE, configuration.meteredOverride);
520         }
521 
522         /**
523          * Write the Configuration data elements for config store from the provided Configuration
524          * to the XML stream.
525          *
526          * @param out XmlSerializer instance pointing to the XML stream.
527          * @param configuration WifiConfiguration object to be serialized.
528          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}.
529          */
writeToXmlForConfigStore( XmlSerializer out, WifiConfiguration configuration, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)530         public static void writeToXmlForConfigStore(
531                 XmlSerializer out, WifiConfiguration configuration,
532                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
533                 throws XmlPullParserException, IOException {
534             writeCommonElementsToXml(out, configuration, encryptionUtil);
535             XmlUtil.writeNextValue(out, XML_TAG_IS_TRUSTED, configuration.trusted);
536             XmlUtil.writeNextValue(out, XML_TAG_IS_OEM_PAID, configuration.oemPaid);
537             XmlUtil.writeNextValue(out, XML_TAG_IS_OEM_PRIVATE, configuration.oemPrivate);
538             XmlUtil.writeNextValue(out, XML_TAG_IS_CARRIER_MERGED,
539                     configuration.carrierMerged);
540             XmlUtil.writeNextValue(out, XML_TAG_BSSID, configuration.BSSID);
541             XmlUtil.writeNextValue(out, XML_TAG_STATUS, configuration.status);
542             XmlUtil.writeNextValue(out, XML_TAG_FQDN, configuration.FQDN);
543             XmlUtil.writeNextValue(
544                     out, XML_TAG_PROVIDER_FRIENDLY_NAME, configuration.providerFriendlyName);
545             XmlUtil.writeNextValue(
546                     out, XML_TAG_LINKED_NETWORKS_LIST, configuration.linkedConfigurations);
547             XmlUtil.writeNextValue(
548                     out, XML_TAG_DEFAULT_GW_MAC_ADDRESS, configuration.defaultGwMacAddress);
549             XmlUtil.writeNextValue(
550                     out, XML_TAG_VALIDATED_INTERNET_ACCESS, configuration.validatedInternetAccess);
551             XmlUtil.writeNextValue(
552                     out, XML_TAG_NO_INTERNET_ACCESS_EXPECTED,
553                     configuration.noInternetAccessExpected);
554             XmlUtil.writeNextValue(out, XML_TAG_METERED_HINT, configuration.meteredHint);
555             XmlUtil.writeNextValue(out, XML_TAG_METERED_OVERRIDE, configuration.meteredOverride);
556             XmlUtil.writeNextValue(
557                     out, XML_TAG_USE_EXTERNAL_SCORES, configuration.useExternalScores);
558             XmlUtil.writeNextValue(out, XML_TAG_CREATOR_UID, configuration.creatorUid);
559             XmlUtil.writeNextValue(out, XML_TAG_CREATOR_NAME, configuration.creatorName);
560             XmlUtil.writeNextValue(out, XML_TAG_LAST_UPDATE_UID, configuration.lastUpdateUid);
561             XmlUtil.writeNextValue(out, XML_TAG_LAST_UPDATE_NAME, configuration.lastUpdateName);
562             XmlUtil.writeNextValue(out, XML_TAG_LAST_CONNECT_UID, configuration.lastConnectUid);
563             XmlUtil.writeNextValue(
564                     out, XML_TAG_IS_LEGACY_PASSPOINT_CONFIG,
565                     configuration.isLegacyPasspointConfig);
566             XmlUtil.writeNextValue(
567                     out, XML_TAG_ROAMING_CONSORTIUM_OIS, configuration.roamingConsortiumIds);
568             XmlUtil.writeNextValue(out, XML_TAG_RANDOMIZED_MAC_ADDRESS,
569                     configuration.getRandomizedMacAddress().toString());
570             XmlUtil.writeNextValue(out, XML_TAG_MAC_RANDOMIZATION_SETTING,
571                     configuration.macRandomizationSetting);
572             XmlUtil.writeNextValue(out, XML_TAG_CARRIER_ID, configuration.carrierId);
573             XmlUtil.writeNextValue(out, XML_TAG_IS_MOST_RECENTLY_CONNECTED,
574                     configuration.isMostRecentlyConnected);
575             XmlUtil.writeNextValue(out, XML_TAG_SUBSCRIPTION_ID, configuration.subscriptionId);
576         }
577 
578         /**
579          * Populate wepKeys array elements only if they were non-empty in the backup data.
580          *
581          * @throws XmlPullParserException if parsing errors occur.
582          */
populateWepKeysFromXmlValue(Object value, String[] wepKeys)583         private static void populateWepKeysFromXmlValue(Object value, String[] wepKeys)
584                 throws XmlPullParserException, IOException {
585             String[] wepKeysInData = (String[]) value;
586             if (wepKeysInData == null) {
587                 return;
588             }
589             if (wepKeysInData.length != wepKeys.length) {
590                 throw new XmlPullParserException(
591                         "Invalid Wep Keys length: " + wepKeysInData.length);
592             }
593             for (int i = 0; i < wepKeys.length; i++) {
594                 if (wepKeysInData[i].isEmpty()) {
595                     wepKeys[i] = null;
596                 } else {
597                     wepKeys[i] = wepKeysInData[i];
598                 }
599             }
600         }
601 
parseSecurityParamsFromXml( XmlPullParser in, int outerTagDepth)602         private static SecurityParams parseSecurityParamsFromXml(
603                 XmlPullParser in, int outerTagDepth) throws XmlPullParserException, IOException {
604             SecurityParams params = null;
605             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
606                 String[] valueName = new String[1];
607                 Object value = XmlUtil.readCurrentValue(in, valueName);
608                 String tagName = valueName[0];
609                 if (tagName == null) {
610                     throw new XmlPullParserException("Missing value name");
611                 }
612                 switch (tagName) {
613                     case WifiConfigurationXmlUtil.XML_TAG_SECURITY_TYPE:
614                         params = SecurityParams.createSecurityParamsBySecurityType((int) value);
615                         break;
616                     case WifiConfigurationXmlUtil.XML_TAG_SAE_IS_H2E_ONLY_MODE:
617                         if (null == params) {
618                             throw new XmlPullParserException("Missing security type.");
619                         }
620                         params.enableSaeH2eOnlyMode((boolean) value);
621                         break;
622                     case WifiConfigurationXmlUtil.XML_TAG_SAE_IS_PK_ONLY_MODE:
623                         if (null == params) {
624                             throw new XmlPullParserException("Missing security type.");
625                         }
626                         params.enableSaePkOnlyMode((boolean) value);
627                         break;
628                     case WifiConfigurationXmlUtil.XML_TAG_IS_ADDED_BY_AUTO_UPGRADE:
629                         if (null == params) {
630                             throw new XmlPullParserException("Missing security type.");
631                         }
632                         params.setIsAddedByAutoUpgrade((boolean) value);
633                         break;
634                 }
635             }
636             return params;
637         }
638 
parseSecurityParamsListFromXml( XmlPullParser in, int outerTagDepth, WifiConfiguration configuration)639         private static void parseSecurityParamsListFromXml(
640                 XmlPullParser in, int outerTagDepth,
641                 WifiConfiguration configuration)
642                 throws XmlPullParserException, IOException {
643             List<SecurityParams> paramsList = new ArrayList<>();
644             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
645                 switch (in.getName()) {
646                     case WifiConfigurationXmlUtil.XML_TAG_SECURITY_PARAMS:
647                         SecurityParams params = parseSecurityParamsFromXml(in, outerTagDepth + 1);
648                         if (params != null) {
649                             paramsList.add(params);
650                         }
651                         break;
652                 }
653             }
654             if (!paramsList.isEmpty()) {
655                 configuration.setSecurityParams(paramsList);
656             }
657         }
658 
659         /**
660          * Parses the configuration data elements from the provided XML stream to a
661          * WifiConfiguration object.
662          * Note: This is used for parsing both backup data and config store data. Looping through
663          * the tags make it easy to add or remove elements in the future versions if needed.
664          *
665          * @param in XmlPullParser instance pointing to the XML stream.
666          * @param outerTagDepth depth of the outer tag in the XML document.
667          * @param shouldExpectEncryptedCredentials Whether to expect encrypted credentials or not.
668          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}.
669          * @param fromSuggestion Is this WifiConfiguration created from a WifiNetworkSuggestion.
670          * @return Pair<Config key, WifiConfiguration object> if parsing is successful,
671          * null otherwise.
672          */
parseFromXml( XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, boolean fromSuggestion)673         public static Pair<String, WifiConfiguration> parseFromXml(
674                 XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials,
675                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil, boolean fromSuggestion)
676                 throws XmlPullParserException, IOException {
677             WifiConfiguration configuration = new WifiConfiguration();
678             String configKeyInData = null;
679             boolean macRandomizationSettingExists = false;
680 
681             // Loop through and parse out all the elements from the stream within this section.
682             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
683                 if (in.getAttributeValue(null, "name") != null) {
684                     // Value elements.
685                     String[] valueName = new String[1];
686                     Object value = XmlUtil.readCurrentValue(in, valueName);
687                     if (valueName[0] == null) {
688                         throw new XmlPullParserException("Missing value name");
689                     }
690                     switch (valueName[0]) {
691                         case XML_TAG_CONFIG_KEY:
692                             configKeyInData = (String) value;
693                             break;
694                         case XML_TAG_SSID:
695                             configuration.SSID = (String) value;
696                             break;
697                         case XML_TAG_BSSID:
698                             configuration.BSSID = (String) value;
699                             break;
700                         case XML_TAG_PRE_SHARED_KEY:
701                             configuration.preSharedKey = (String) value;
702                             break;
703                         case XML_TAG_WEP_KEYS:
704                             populateWepKeysFromXmlValue(value, configuration.wepKeys);
705                             break;
706                         case XML_TAG_WEP_TX_KEY_INDEX:
707                             configuration.wepTxKeyIndex = (int) value;
708                             break;
709                         case XML_TAG_HIDDEN_SSID:
710                             configuration.hiddenSSID = (boolean) value;
711                             break;
712                         case XML_TAG_REQUIRE_PMF:
713                             configuration.requirePmf = (boolean) value;
714                             break;
715                         case XML_TAG_ALLOWED_KEY_MGMT:
716                             byte[] allowedKeyMgmt = (byte[]) value;
717                             configuration.allowedKeyManagement = BitSet.valueOf(allowedKeyMgmt);
718                             break;
719                         case XML_TAG_ALLOWED_PROTOCOLS:
720                             byte[] allowedProtocols = (byte[]) value;
721                             configuration.allowedProtocols = BitSet.valueOf(allowedProtocols);
722                             break;
723                         case XML_TAG_ALLOWED_AUTH_ALGOS:
724                             byte[] allowedAuthAlgorithms = (byte[]) value;
725                             configuration.allowedAuthAlgorithms = BitSet.valueOf(
726                                     allowedAuthAlgorithms);
727                             break;
728                         case XML_TAG_ALLOWED_GROUP_CIPHERS:
729                             byte[] allowedGroupCiphers = (byte[]) value;
730                             configuration.allowedGroupCiphers = BitSet.valueOf(allowedGroupCiphers);
731                             break;
732                         case XML_TAG_ALLOWED_PAIRWISE_CIPHERS:
733                             byte[] allowedPairwiseCiphers = (byte[]) value;
734                             configuration.allowedPairwiseCiphers =
735                                     BitSet.valueOf(allowedPairwiseCiphers);
736                             break;
737                         case XML_TAG_ALLOWED_GROUP_MGMT_CIPHERS:
738                             byte[] allowedGroupMgmtCiphers = (byte[]) value;
739                             configuration.allowedGroupManagementCiphers =
740                                     BitSet.valueOf(allowedGroupMgmtCiphers);
741                             break;
742                         case XML_TAG_ALLOWED_SUITE_B_CIPHERS:
743                             byte[] allowedSuiteBCiphers = (byte[]) value;
744                             configuration.allowedSuiteBCiphers =
745                                     BitSet.valueOf(allowedSuiteBCiphers);
746                             break;
747                         case XML_TAG_SHARED:
748                             configuration.shared = (boolean) value;
749                             break;
750                         case XML_TAG_STATUS:
751                             int status = (int) value;
752                             // Any network which was CURRENT before reboot needs
753                             // to be restored to ENABLED.
754                             if (status == WifiConfiguration.Status.CURRENT) {
755                                 status = WifiConfiguration.Status.ENABLED;
756                             }
757                             configuration.status = status;
758                             break;
759                         case XML_TAG_FQDN:
760                             configuration.FQDN = (String) value;
761                             break;
762                         case XML_TAG_PROVIDER_FRIENDLY_NAME:
763                             configuration.providerFriendlyName = (String) value;
764                             break;
765                         case XML_TAG_LINKED_NETWORKS_LIST:
766                             configuration.linkedConfigurations = (HashMap<String, Integer>) value;
767                             break;
768                         case XML_TAG_DEFAULT_GW_MAC_ADDRESS:
769                             configuration.defaultGwMacAddress = (String) value;
770                             break;
771                         case XML_TAG_VALIDATED_INTERNET_ACCESS:
772                             configuration.validatedInternetAccess = (boolean) value;
773                             break;
774                         case XML_TAG_NO_INTERNET_ACCESS_EXPECTED:
775                             configuration.noInternetAccessExpected = (boolean) value;
776                             break;
777                         case XML_TAG_METERED_HINT:
778                             configuration.meteredHint = (boolean) value;
779                             break;
780                         case XML_TAG_METERED_OVERRIDE:
781                             configuration.meteredOverride = (int) value;
782                             break;
783                         case XML_TAG_USE_EXTERNAL_SCORES:
784                             configuration.useExternalScores = (boolean) value;
785                             break;
786                         case XML_TAG_CREATOR_UID:
787                             configuration.creatorUid = (int) value;
788                             break;
789                         case XML_TAG_CREATOR_NAME:
790                             configuration.creatorName = (String) value;
791                             break;
792                         case XML_TAG_LAST_UPDATE_UID:
793                             configuration.lastUpdateUid = (int) value;
794                             break;
795                         case XML_TAG_LAST_UPDATE_NAME:
796                             configuration.lastUpdateName = (String) value;
797                             break;
798                         case XML_TAG_LAST_CONNECT_UID:
799                             configuration.lastConnectUid = (int) value;
800                             break;
801                         case XML_TAG_IS_LEGACY_PASSPOINT_CONFIG:
802                             configuration.isLegacyPasspointConfig = (boolean) value;
803                             break;
804                         case XML_TAG_ROAMING_CONSORTIUM_OIS:
805                             configuration.roamingConsortiumIds = (long[]) value;
806                             break;
807                         case XML_TAG_RANDOMIZED_MAC_ADDRESS:
808                             configuration.setRandomizedMacAddress(
809                                     MacAddress.fromString((String) value));
810                             break;
811                         case XML_TAG_MAC_RANDOMIZATION_SETTING:
812                             configuration.macRandomizationSetting = (int) value;
813                             macRandomizationSettingExists = true;
814                             break;
815                         case XML_TAG_CARRIER_ID:
816                             configuration.carrierId = (int) value;
817                             break;
818                         case XML_TAG_SUBSCRIPTION_ID:
819                             configuration.subscriptionId = (int) value;
820                             break;
821                         case XML_TAG_IS_AUTO_JOIN:
822                             configuration.allowAutojoin = (boolean) value;
823                             break;
824                         case XML_TAG_DELETION_PRIORITY:
825                             configuration.setDeletionPriority((int) value);
826                             break;
827                         case XML_TAG_NUM_REBOOTS_SINCE_LAST_USE:
828                             configuration.numRebootsSinceLastUse = (int) value;
829                             break;
830                         case XML_TAG_IS_TRUSTED:
831                             configuration.trusted = (boolean) value;
832                             break;
833                         case XML_TAG_IS_OEM_PAID:
834                             configuration.oemPaid = (boolean) value;
835                             break;
836                         case XML_TAG_IS_OEM_PRIVATE:
837                             configuration.oemPrivate = (boolean) value;
838                             break;
839                         case XML_TAG_IS_MOST_RECENTLY_CONNECTED:
840                             configuration.isMostRecentlyConnected = (boolean) value;
841                             break;
842                         case XML_TAG_IS_CARRIER_MERGED:
843                             configuration.carrierMerged = (boolean) value;
844                         default:
845                             Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]);
846                             break;
847                     }
848                 } else {
849                     String tagName = in.getName();
850                     if (tagName == null) {
851                         throw new XmlPullParserException("Unexpected null tag found");
852                     }
853                     switch (tagName) {
854                         case XML_TAG_PRE_SHARED_KEY:
855                             if (!shouldExpectEncryptedCredentials || encryptionUtil == null) {
856                                 throw new XmlPullParserException(
857                                         "Encrypted preSharedKey section not expected");
858                             }
859                             EncryptedData encryptedData =
860                                     EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1);
861                             byte[] preSharedKeyBytes = encryptionUtil.decrypt(encryptedData);
862                             if (preSharedKeyBytes == null) {
863                                 Log.wtf(TAG, "Decryption of preSharedKey failed");
864                             } else {
865                                 configuration.preSharedKey = new String(preSharedKeyBytes);
866                             }
867                             break;
868                         case XML_TAG_SECURITY_PARAMS_LIST:
869                             parseSecurityParamsListFromXml(in, outerTagDepth + 1, configuration);
870                             break;
871                         default:
872                             Log.w(TAG, "Ignoring unknown tag found: " + tagName);
873                             break;
874                     }
875                 }
876             }
877             if (!macRandomizationSettingExists) {
878                 configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_NONE;
879             }
880             if (configuration.macRandomizationSetting
881                     == WifiConfiguration.RANDOMIZATION_PERSISTENT && !fromSuggestion) {
882                 configuration.macRandomizationSetting = WifiConfiguration.RANDOMIZATION_AUTO;
883             }
884             configuration.convertLegacyFieldsToSecurityParamsIfNeeded();
885             return Pair.create(configKeyInData, configuration);
886         }
887     }
888 
889     /**
890      * Utility class to serialize and deseriaize {@link IpConfiguration} object to XML & vice versa.
891      * This is used by both {@link com.android.server.wifi.WifiConfigStore} &
892      * {@link com.android.server.wifi.WifiBackupRestore} modules.
893      */
894     public static class IpConfigurationXmlUtil {
895 
896         /**
897          * List of XML tags corresponding to IpConfiguration object elements.
898          */
899         public static final String XML_TAG_IP_ASSIGNMENT = "IpAssignment";
900         public static final String XML_TAG_LINK_ADDRESS = "LinkAddress";
901         public static final String XML_TAG_LINK_PREFIX_LENGTH = "LinkPrefixLength";
902         public static final String XML_TAG_GATEWAY_ADDRESS = "GatewayAddress";
903         public static final String XML_TAG_DNS_SERVER_ADDRESSES = "DNSServers";
904         public static final String XML_TAG_PROXY_SETTINGS = "ProxySettings";
905         public static final String XML_TAG_PROXY_HOST = "ProxyHost";
906         public static final String XML_TAG_PROXY_PORT = "ProxyPort";
907         public static final String XML_TAG_PROXY_PAC_FILE = "ProxyPac";
908         public static final String XML_TAG_PROXY_EXCLUSION_LIST = "ProxyExclusionList";
909 
parseProxyExclusionListString( @ullable String exclusionListString)910         private static List<String> parseProxyExclusionListString(
911                 @Nullable String exclusionListString) {
912             if (exclusionListString == null) {
913                 return Collections.emptyList();
914             } else {
915                 return Arrays.asList(exclusionListString.toLowerCase(Locale.ROOT).split(","));
916             }
917         }
918 
generateProxyExclusionListString(@onNull String[] exclusionList)919         private static String generateProxyExclusionListString(@NonNull String[] exclusionList) {
920             return TextUtils.join(",", exclusionList);
921         }
922 
923         /**
924          * Write the static IP configuration data elements to XML stream.
925          */
writeStaticIpConfigurationToXml( XmlSerializer out, StaticIpConfiguration staticIpConfiguration)926         private static void writeStaticIpConfigurationToXml(
927                 XmlSerializer out, StaticIpConfiguration staticIpConfiguration)
928                 throws XmlPullParserException, IOException {
929             if (staticIpConfiguration.getIpAddress() != null) {
930                 XmlUtil.writeNextValue(
931                         out, XML_TAG_LINK_ADDRESS,
932                         staticIpConfiguration.getIpAddress().getAddress().getHostAddress());
933                 XmlUtil.writeNextValue(
934                         out, XML_TAG_LINK_PREFIX_LENGTH,
935                         staticIpConfiguration.getIpAddress().getPrefixLength());
936             } else {
937                 XmlUtil.writeNextValue(
938                         out, XML_TAG_LINK_ADDRESS, null);
939                 XmlUtil.writeNextValue(
940                         out, XML_TAG_LINK_PREFIX_LENGTH, null);
941             }
942             if (staticIpConfiguration.getGateway() != null) {
943                 XmlUtil.writeNextValue(
944                         out, XML_TAG_GATEWAY_ADDRESS,
945                         staticIpConfiguration.getGateway().getHostAddress());
946             } else {
947                 XmlUtil.writeNextValue(
948                         out, XML_TAG_GATEWAY_ADDRESS, null);
949 
950             }
951             // Create a string array of DNS server addresses
952             String[] dnsServers = new String[staticIpConfiguration.getDnsServers().size()];
953             int dnsServerIdx = 0;
954             for (InetAddress inetAddr : staticIpConfiguration.getDnsServers()) {
955                 dnsServers[dnsServerIdx++] = inetAddr.getHostAddress();
956             }
957             XmlUtil.writeNextValue(
958                     out, XML_TAG_DNS_SERVER_ADDRESSES, dnsServers);
959         }
960 
961         /**
962          * Write the IP configuration data elements from the provided Configuration to the XML
963          * stream.
964          *
965          * @param out             XmlSerializer instance pointing to the XML stream.
966          * @param ipConfiguration IpConfiguration object to be serialized.
967          */
writeToXml(XmlSerializer out, IpConfiguration ipConfiguration)968         public static void writeToXml(XmlSerializer out, IpConfiguration ipConfiguration)
969                 throws XmlPullParserException, IOException {
970             // Write IP assignment settings
971             XmlUtil.writeNextValue(out, XML_TAG_IP_ASSIGNMENT,
972                     ipConfiguration.getIpAssignment().toString());
973             switch (ipConfiguration.getIpAssignment()) {
974                 case STATIC:
975                     writeStaticIpConfigurationToXml(
976                             out, ipConfiguration.getStaticIpConfiguration());
977                     break;
978                 case DHCP:
979                 case UNASSIGNED:
980                     break;
981                 default:
982                     Log.w(TAG, "Ignoring unknown ip assignment type: "
983                             + ipConfiguration.getIpAssignment());
984                     break;
985             }
986 
987             // Write proxy settings
988             XmlUtil.writeNextValue(
989                     out, XML_TAG_PROXY_SETTINGS,
990                     ipConfiguration.getProxySettings().toString());
991             switch (ipConfiguration.getProxySettings()) {
992                 case STATIC:
993                     XmlUtil.writeNextValue(
994                             out, XML_TAG_PROXY_HOST,
995                             ipConfiguration.getHttpProxy().getHost());
996                     XmlUtil.writeNextValue(
997                             out, XML_TAG_PROXY_PORT,
998                             ipConfiguration.getHttpProxy().getPort());
999                     XmlUtil.writeNextValue(
1000                             out, XML_TAG_PROXY_EXCLUSION_LIST,
1001                             generateProxyExclusionListString(
1002                                     ipConfiguration.getHttpProxy().getExclusionList()));
1003                     break;
1004                 case PAC:
1005                     XmlUtil.writeNextValue(
1006                             out, XML_TAG_PROXY_PAC_FILE,
1007                             ipConfiguration.getHttpProxy().getPacFileUrl().toString());
1008                     break;
1009                 case NONE:
1010                 case UNASSIGNED:
1011                     break;
1012                 default:
1013                     Log.w(TAG, "Ignoring unknown proxy settings type: "
1014                             + ipConfiguration.getProxySettings());
1015                     break;
1016             }
1017         }
1018 
1019         /**
1020          * Parse out the static IP configuration from the XML stream.
1021          */
parseStaticIpConfigurationFromXml(XmlPullParser in)1022         private static StaticIpConfiguration parseStaticIpConfigurationFromXml(XmlPullParser in)
1023                 throws XmlPullParserException, IOException {
1024             StaticIpConfiguration.Builder builder = new StaticIpConfiguration.Builder();
1025 
1026             String linkAddressString =
1027                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_ADDRESS);
1028             Integer linkPrefixLength =
1029                     (Integer) XmlUtil.readNextValueWithName(in, XML_TAG_LINK_PREFIX_LENGTH);
1030             if (linkAddressString != null && linkPrefixLength != null) {
1031                 LinkAddress linkAddress = new LinkAddress(
1032                         InetAddresses.parseNumericAddress(linkAddressString),
1033                         linkPrefixLength);
1034                 if (linkAddress.getAddress() instanceof Inet4Address) {
1035                     builder.setIpAddress(linkAddress);
1036                 } else {
1037                     Log.w(TAG, "Non-IPv4 address: " + linkAddress);
1038                 }
1039             }
1040             String gatewayAddressString =
1041                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_GATEWAY_ADDRESS);
1042             if (gatewayAddressString != null) {
1043                 InetAddress gateway =
1044                         InetAddresses.parseNumericAddress(gatewayAddressString);
1045                 RouteInfo route = new RouteInfo(null, gateway, null, RouteInfo.RTN_UNICAST);
1046                 if (route.isDefaultRoute()
1047                         && route.getDestination().getAddress() instanceof Inet4Address) {
1048                     builder.setGateway(gateway);
1049                 } else {
1050                     Log.w(TAG, "Non-IPv4 default route: " + route);
1051                 }
1052             }
1053             String[] dnsServerAddressesString =
1054                     (String[]) XmlUtil.readNextValueWithName(in, XML_TAG_DNS_SERVER_ADDRESSES);
1055             if (dnsServerAddressesString != null) {
1056                 List<InetAddress> dnsServerAddresses = new ArrayList<>();
1057                 for (String dnsServerAddressString : dnsServerAddressesString) {
1058                     InetAddress dnsServerAddress =
1059                             InetAddresses.parseNumericAddress(dnsServerAddressString);
1060                     dnsServerAddresses.add(dnsServerAddress);
1061                 }
1062                 builder.setDnsServers(dnsServerAddresses);
1063             }
1064             return builder.build();
1065         }
1066 
1067         /**
1068          * Parses the IP configuration data elements from the provided XML stream to an
1069          * IpConfiguration object.
1070          *
1071          * @param in            XmlPullParser instance pointing to the XML stream.
1072          * @param outerTagDepth depth of the outer tag in the XML document.
1073          * @return IpConfiguration object if parsing is successful, null otherwise.
1074          */
parseFromXml(XmlPullParser in, int outerTagDepth)1075         public static IpConfiguration parseFromXml(XmlPullParser in, int outerTagDepth)
1076                 throws XmlPullParserException, IOException {
1077             IpConfiguration ipConfiguration = new IpConfiguration();
1078 
1079             // Parse out the IP assignment info first.
1080             String ipAssignmentString =
1081                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_IP_ASSIGNMENT);
1082             IpAssignment ipAssignment = IpAssignment.valueOf(ipAssignmentString);
1083             ipConfiguration.setIpAssignment(ipAssignment);
1084             switch (ipAssignment) {
1085                 case STATIC:
1086                     ipConfiguration.setStaticIpConfiguration(parseStaticIpConfigurationFromXml(in));
1087                     break;
1088                 case DHCP:
1089                 case UNASSIGNED:
1090                     break;
1091                 default:
1092                     Log.w(TAG, "Ignoring unknown ip assignment type: " + ipAssignment);
1093                     break;
1094             }
1095 
1096             // Parse out the proxy settings next.
1097             String proxySettingsString =
1098                     (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_SETTINGS);
1099             ProxySettings proxySettings = ProxySettings.valueOf(proxySettingsString);
1100             ipConfiguration.setProxySettings(proxySettings);
1101             switch (proxySettings) {
1102                 case STATIC:
1103                     String proxyHost =
1104                             (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_HOST);
1105                     int proxyPort =
1106                             (int) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PORT);
1107                     String proxyExclusionList =
1108                             (String) XmlUtil.readNextValueWithName(
1109                                     in, XML_TAG_PROXY_EXCLUSION_LIST);
1110                     ipConfiguration.setHttpProxy(
1111                             ProxyInfo.buildDirectProxy(
1112                                     proxyHost, proxyPort,
1113                                     parseProxyExclusionListString(proxyExclusionList)));
1114                     break;
1115                 case PAC:
1116                     String proxyPacFile =
1117                             (String) XmlUtil.readNextValueWithName(in, XML_TAG_PROXY_PAC_FILE);
1118                     ipConfiguration.setHttpProxy(
1119                             ProxyInfo.buildPacProxy(Uri.parse(proxyPacFile)));
1120                     break;
1121                 case NONE:
1122                 case UNASSIGNED:
1123                     break;
1124                 default:
1125                     Log.w(TAG, "Ignoring unknown proxy settings type: " + proxySettings);
1126                     break;
1127             }
1128             return ipConfiguration;
1129         }
1130     }
1131 
1132     /**
1133      * Utility class to serialize and deserialize {@link NetworkSelectionStatus} object to XML &
1134      * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module.
1135      */
1136     public static class NetworkSelectionStatusXmlUtil {
1137 
1138         /**
1139          * List of XML tags corresponding to NetworkSelectionStatus object elements.
1140          */
1141         public static final String XML_TAG_SELECTION_STATUS = "SelectionStatus";
1142         public static final String XML_TAG_DISABLE_REASON = "DisableReason";
1143         public static final String XML_TAG_CONNECT_CHOICE = "ConnectChoice";
1144         public static final String XML_TAG_HAS_EVER_CONNECTED = "HasEverConnected";
1145         public static final String XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED =
1146                 "CaptivePortalNeverDetected";
1147         public static final String XML_TAG_CONNECT_CHOICE_RSSI = "ConnectChoiceRssi";
1148 
1149         /**
1150          * Write the NetworkSelectionStatus data elements from the provided status to the XML
1151          * stream.
1152          *
1153          * @param out             XmlSerializer instance pointing to the XML stream.
1154          * @param selectionStatus NetworkSelectionStatus object to be serialized.
1155          */
writeToXml(XmlSerializer out, NetworkSelectionStatus selectionStatus)1156         public static void writeToXml(XmlSerializer out, NetworkSelectionStatus selectionStatus)
1157                 throws XmlPullParserException, IOException {
1158             XmlUtil.writeNextValue(
1159                     out, XML_TAG_SELECTION_STATUS, selectionStatus.getNetworkStatusString());
1160             XmlUtil.writeNextValue(
1161                     out, XML_TAG_DISABLE_REASON,
1162                     selectionStatus.getNetworkSelectionDisableReasonString());
1163             XmlUtil.writeNextValue(out, XML_TAG_CONNECT_CHOICE, selectionStatus.getConnectChoice());
1164             XmlUtil.writeNextValue(out, XML_TAG_CONNECT_CHOICE_RSSI,
1165                     selectionStatus.getConnectChoiceRssi());
1166             XmlUtil.writeNextValue(
1167                     out, XML_TAG_HAS_EVER_CONNECTED, selectionStatus.hasEverConnected());
1168             XmlUtil.writeNextValue(out, XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED,
1169                     selectionStatus.hasNeverDetectedCaptivePortal());
1170         }
1171 
1172         /**
1173          * Parses the NetworkSelectionStatus data elements from the provided XML stream to a
1174          * NetworkSelectionStatus object.
1175          *
1176          * @param in            XmlPullParser instance pointing to the XML stream.
1177          * @param outerTagDepth depth of the outer tag in the XML document.
1178          * @return NetworkSelectionStatus object if parsing is successful, null otherwise.
1179          */
parseFromXml(XmlPullParser in, int outerTagDepth)1180         public static NetworkSelectionStatus parseFromXml(XmlPullParser in, int outerTagDepth)
1181                 throws XmlPullParserException, IOException {
1182             NetworkSelectionStatus selectionStatus = new NetworkSelectionStatus();
1183             String statusString = "";
1184             String disableReasonString = "";
1185             // Initialize hasNeverDetectedCaptivePortal to "false" for upgrading legacy configs
1186             // which do not have the XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED tag.
1187             selectionStatus.setHasNeverDetectedCaptivePortal(false);
1188 
1189             // Loop through and parse out all the elements from the stream within this section.
1190             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1191                 String[] valueName = new String[1];
1192                 Object value = XmlUtil.readCurrentValue(in, valueName);
1193                 if (valueName[0] == null) {
1194                     throw new XmlPullParserException("Missing value name");
1195                 }
1196                 switch (valueName[0]) {
1197                     case XML_TAG_SELECTION_STATUS:
1198                         statusString = (String) value;
1199                         break;
1200                     case XML_TAG_DISABLE_REASON:
1201                         disableReasonString = (String) value;
1202                         break;
1203                     case XML_TAG_CONNECT_CHOICE:
1204                         selectionStatus.setConnectChoice((String) value);
1205                         break;
1206                     case XML_TAG_CONNECT_CHOICE_RSSI:
1207                         selectionStatus.setConnectChoiceRssi((int) value);
1208                         break;
1209                     case XML_TAG_HAS_EVER_CONNECTED:
1210                         selectionStatus.setHasEverConnected((boolean) value);
1211                         break;
1212                     case XML_TAG_IS_CAPTIVE_PORTAL_NEVER_DETECTED:
1213                         selectionStatus.setHasNeverDetectedCaptivePortal((boolean) value);
1214                     default:
1215                         Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]);
1216                         break;
1217                 }
1218             }
1219             // Now figure out the network selection status codes from |selectionStatusString| &
1220             // |disableReasonString|.
1221             int status =
1222                     Arrays.asList(NetworkSelectionStatus.QUALITY_NETWORK_SELECTION_STATUS)
1223                             .indexOf(statusString);
1224             int disableReason =
1225                     NetworkSelectionStatus.getDisableReasonByString(disableReasonString);
1226 
1227             // If either of the above codes are invalid or if the network was temporarily disabled
1228             // (blacklisted), restore the status as enabled. We don't want to persist blacklists
1229             // across reboots.
1230             if (status == -1 || disableReason == -1 ||
1231                     status == NetworkSelectionStatus.NETWORK_SELECTION_TEMPORARY_DISABLED) {
1232                 status = NetworkSelectionStatus.NETWORK_SELECTION_ENABLED;
1233                 disableReason = NetworkSelectionStatus.DISABLED_NONE;
1234             }
1235             selectionStatus.setNetworkSelectionStatus(status);
1236             selectionStatus.setNetworkSelectionDisableReason(disableReason);
1237             if (status == NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED) {
1238                 // Make the counter non-zero so that logging code works properly
1239                 selectionStatus.setDisableReasonCounter(disableReason, 1);
1240             }
1241             return selectionStatus;
1242         }
1243     }
1244 
1245     /**
1246      * Utility class to serialize and deseriaize {@link WifiEnterpriseConfig} object to XML &
1247      * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module.
1248      */
1249     public static class WifiEnterpriseConfigXmlUtil {
1250 
1251         /**
1252          * List of XML tags corresponding to WifiEnterpriseConfig object elements.
1253          */
1254         public static final String XML_TAG_IDENTITY = "Identity";
1255         public static final String XML_TAG_ANON_IDENTITY = "AnonIdentity";
1256         public static final String XML_TAG_PASSWORD = "Password";
1257         public static final String XML_TAG_CLIENT_CERT = "ClientCert";
1258         public static final String XML_TAG_CA_CERT = "CaCert";
1259         public static final String XML_TAG_SUBJECT_MATCH = "SubjectMatch";
1260         public static final String XML_TAG_ENGINE = "Engine";
1261         public static final String XML_TAG_ENGINE_ID = "EngineId";
1262         public static final String XML_TAG_PRIVATE_KEY_ID = "PrivateKeyId";
1263         public static final String XML_TAG_ALT_SUBJECT_MATCH = "AltSubjectMatch";
1264         public static final String XML_TAG_DOM_SUFFIX_MATCH = "DomSuffixMatch";
1265         public static final String XML_TAG_CA_PATH = "CaPath";
1266         public static final String XML_TAG_EAP_METHOD = "EapMethod";
1267         public static final String XML_TAG_PHASE2_METHOD = "Phase2Method";
1268         public static final String XML_TAG_PLMN = "PLMN";
1269         public static final String XML_TAG_REALM = "Realm";
1270         public static final String XML_TAG_OCSP = "Ocsp";
1271         public static final String XML_TAG_WAPI_CERT_SUITE = "WapiCertSuite";
1272         public static final String XML_TAG_APP_INSTALLED_ROOT_CA_CERT = "AppInstalledRootCaCert";
1273         public static final String XML_TAG_APP_INSTALLED_PRIVATE_KEY = "AppInstalledPrivateKey";
1274         public static final String XML_TAG_KEYCHAIN_KEY_ALIAS = "KeyChainAlias";
1275         public static final String XML_TAG_DECORATED_IDENTITY_PREFIX = "DecoratedIdentityPrefix";
1276 
1277         /**
1278          * Write password key to the XML stream.
1279          *
1280          * If encryptionUtil is null or if encryption fails for some reason, the password is stored
1281          * in plaintext, else the encrypted psk is stored.
1282          */
writePasswordToXml( XmlSerializer out, String password, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)1283         private static void writePasswordToXml(
1284                 XmlSerializer out, String password,
1285                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
1286                 throws XmlPullParserException, IOException {
1287             EncryptedData encryptedData = null;
1288             if (encryptionUtil != null) {
1289                 if (password != null) {
1290                     encryptedData = encryptionUtil.encrypt(password.getBytes());
1291                     if (encryptedData == null) {
1292                         // We silently fail encryption failures!
1293                         Log.wtf(TAG, "Encryption of password failed");
1294                     }
1295                 }
1296             }
1297             if (encryptedData != null) {
1298                 XmlUtil.writeNextSectionStart(out, XML_TAG_PASSWORD);
1299                 EncryptedDataXmlUtil.writeToXml(out, encryptedData);
1300                 XmlUtil.writeNextSectionEnd(out, XML_TAG_PASSWORD);
1301             } else {
1302                 XmlUtil.writeNextValue(out, XML_TAG_PASSWORD, password);
1303             }
1304         }
1305 
1306         /**
1307          * Write the WifiEnterpriseConfig data elements from the provided config to the XML
1308          * stream.
1309          *
1310          * @param out XmlSerializer instance pointing to the XML stream.
1311          * @param enterpriseConfig WifiEnterpriseConfig object to be serialized.
1312          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}.
1313          */
writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)1314         public static void writeToXml(XmlSerializer out, WifiEnterpriseConfig enterpriseConfig,
1315                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
1316                 throws XmlPullParserException, IOException {
1317             XmlUtil.writeNextValue(out, XML_TAG_IDENTITY,
1318                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.IDENTITY_KEY));
1319             XmlUtil.writeNextValue(out, XML_TAG_ANON_IDENTITY,
1320                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ANON_IDENTITY_KEY));
1321             writePasswordToXml(
1322                     out, enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PASSWORD_KEY),
1323                     encryptionUtil);
1324             XmlUtil.writeNextValue(out, XML_TAG_CLIENT_CERT,
1325                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CLIENT_CERT_KEY));
1326             XmlUtil.writeNextValue(out, XML_TAG_CA_CERT,
1327                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_CERT_KEY));
1328             XmlUtil.writeNextValue(out, XML_TAG_SUBJECT_MATCH,
1329                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.SUBJECT_MATCH_KEY));
1330             XmlUtil.writeNextValue(out, XML_TAG_ENGINE,
1331                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ENGINE_KEY));
1332             XmlUtil.writeNextValue(out, XML_TAG_ENGINE_ID,
1333                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ENGINE_ID_KEY));
1334             XmlUtil.writeNextValue(out, XML_TAG_PRIVATE_KEY_ID,
1335                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY));
1336             XmlUtil.writeNextValue(out, XML_TAG_ALT_SUBJECT_MATCH,
1337                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY));
1338             XmlUtil.writeNextValue(out, XML_TAG_DOM_SUFFIX_MATCH,
1339                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY));
1340             XmlUtil.writeNextValue(out, XML_TAG_CA_PATH,
1341                     enterpriseConfig.getFieldValue(WifiEnterpriseConfig.CA_PATH_KEY));
1342             XmlUtil.writeNextValue(out, XML_TAG_EAP_METHOD, enterpriseConfig.getEapMethod());
1343             XmlUtil.writeNextValue(out, XML_TAG_PHASE2_METHOD, enterpriseConfig.getPhase2Method());
1344             XmlUtil.writeNextValue(out, XML_TAG_PLMN, enterpriseConfig.getPlmn());
1345             XmlUtil.writeNextValue(out, XML_TAG_REALM, enterpriseConfig.getRealm());
1346             XmlUtil.writeNextValue(out, XML_TAG_OCSP, enterpriseConfig.getOcsp());
1347             XmlUtil.writeNextValue(out,
1348                     XML_TAG_WAPI_CERT_SUITE, enterpriseConfig.getWapiCertSuite());
1349             XmlUtil.writeNextValue(out, XML_TAG_APP_INSTALLED_ROOT_CA_CERT,
1350                     enterpriseConfig.isAppInstalledCaCert());
1351             XmlUtil.writeNextValue(out, XML_TAG_APP_INSTALLED_PRIVATE_KEY,
1352                     enterpriseConfig.isAppInstalledDeviceKeyAndCert());
1353             XmlUtil.writeNextValue(out, XML_TAG_KEYCHAIN_KEY_ALIAS,
1354                     enterpriseConfig.getClientKeyPairAliasInternal());
1355             if (SdkLevel.isAtLeastS()) {
1356                 XmlUtil.writeNextValue(out, XML_TAG_DECORATED_IDENTITY_PREFIX,
1357                         enterpriseConfig.getDecoratedIdentityPrefix());
1358             }
1359         }
1360 
1361         /**
1362          * Parses the data elements from the provided XML stream to a WifiEnterpriseConfig object.
1363          *
1364          * @param in XmlPullParser instance pointing to the XML stream.
1365          * @param outerTagDepth depth of the outer tag in the XML document.
1366          * @param shouldExpectEncryptedCredentials Whether to expect encrypted credentials or not.
1367          * @param encryptionUtil Instance of {@link EncryptedDataXmlUtil}.
1368          * @return WifiEnterpriseConfig object if parsing is successful, null otherwise.
1369          */
parseFromXml(XmlPullParser in, int outerTagDepth, boolean shouldExpectEncryptedCredentials, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)1370         public static WifiEnterpriseConfig parseFromXml(XmlPullParser in, int outerTagDepth,
1371                 boolean shouldExpectEncryptedCredentials,
1372                 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)
1373                 throws XmlPullParserException, IOException {
1374             WifiEnterpriseConfig enterpriseConfig = new WifiEnterpriseConfig();
1375 
1376             // Loop through and parse out all the elements from the stream within this section.
1377             while (XmlUtilHelper.nextElementWithin(in, outerTagDepth)) {
1378                 if (in.getAttributeValue(null, "name") != null) {
1379                     // Value elements.
1380                     String[] valueName = new String[1];
1381                     Object value = XmlUtil.readCurrentValue(in, valueName);
1382                     if (valueName[0] == null) {
1383                         throw new XmlPullParserException("Missing value name");
1384                     }
1385                     switch (valueName[0]) {
1386                         case XML_TAG_IDENTITY:
1387                             enterpriseConfig.setFieldValue(
1388                                     WifiEnterpriseConfig.IDENTITY_KEY, (String) value);
1389                             break;
1390                         case XML_TAG_ANON_IDENTITY:
1391                             enterpriseConfig.setFieldValue(
1392                                     WifiEnterpriseConfig.ANON_IDENTITY_KEY, (String) value);
1393                             break;
1394                         case XML_TAG_PASSWORD:
1395                             enterpriseConfig.setFieldValue(
1396                                     WifiEnterpriseConfig.PASSWORD_KEY, (String) value);
1397                             if (shouldExpectEncryptedCredentials
1398                                     && !TextUtils.isEmpty(enterpriseConfig.getFieldValue(
1399                                     WifiEnterpriseConfig.PASSWORD_KEY))) {
1400                                 // Indicates that encryption of password failed when it was last
1401                                 // written.
1402                                 Log.e(TAG, "password value not expected");
1403                             }
1404                             break;
1405                         case XML_TAG_CLIENT_CERT:
1406                             enterpriseConfig.setFieldValue(
1407                                     WifiEnterpriseConfig.CLIENT_CERT_KEY, (String) value);
1408                             break;
1409                         case XML_TAG_CA_CERT:
1410                             enterpriseConfig.setFieldValue(
1411                                     WifiEnterpriseConfig.CA_CERT_KEY, (String) value);
1412                             break;
1413                         case XML_TAG_SUBJECT_MATCH:
1414                             enterpriseConfig.setFieldValue(
1415                                     WifiEnterpriseConfig.SUBJECT_MATCH_KEY, (String) value);
1416                             break;
1417                         case XML_TAG_ENGINE:
1418                             enterpriseConfig.setFieldValue(
1419                                     WifiEnterpriseConfig.ENGINE_KEY, (String) value);
1420                             break;
1421                         case XML_TAG_ENGINE_ID:
1422                             enterpriseConfig.setFieldValue(
1423                                     WifiEnterpriseConfig.ENGINE_ID_KEY, (String) value);
1424                             break;
1425                         case XML_TAG_PRIVATE_KEY_ID:
1426                             enterpriseConfig.setFieldValue(
1427                                     WifiEnterpriseConfig.PRIVATE_KEY_ID_KEY, (String) value);
1428                             break;
1429                         case XML_TAG_ALT_SUBJECT_MATCH:
1430                             enterpriseConfig.setFieldValue(
1431                                     WifiEnterpriseConfig.ALTSUBJECT_MATCH_KEY, (String) value);
1432                             break;
1433                         case XML_TAG_DOM_SUFFIX_MATCH:
1434                             enterpriseConfig.setFieldValue(
1435                                     WifiEnterpriseConfig.DOM_SUFFIX_MATCH_KEY, (String) value);
1436                             break;
1437                         case XML_TAG_CA_PATH:
1438                             enterpriseConfig.setFieldValue(
1439                                     WifiEnterpriseConfig.CA_PATH_KEY, (String) value);
1440                             break;
1441                         case XML_TAG_OCSP:
1442                             enterpriseConfig.setOcsp((int) value);
1443                             break;
1444                         case XML_TAG_EAP_METHOD:
1445                             enterpriseConfig.setEapMethod((int) value);
1446                             break;
1447                         case XML_TAG_PHASE2_METHOD:
1448                             enterpriseConfig.setPhase2Method((int) value);
1449                             break;
1450                         case XML_TAG_PLMN:
1451                             enterpriseConfig.setPlmn((String) value);
1452                             break;
1453                         case XML_TAG_REALM:
1454                             enterpriseConfig.setRealm((String) value);
1455                             break;
1456                         case XML_TAG_WAPI_CERT_SUITE:
1457                             enterpriseConfig.setWapiCertSuite((String) value);
1458                             break;
1459                         case XML_TAG_APP_INSTALLED_ROOT_CA_CERT:
1460                             enterpriseConfig.initIsAppInstalledCaCert((boolean) value);
1461                             break;
1462                         case XML_TAG_APP_INSTALLED_PRIVATE_KEY:
1463                             enterpriseConfig.initIsAppInstalledDeviceKeyAndCert((boolean) value);
1464                             break;
1465                         case XML_TAG_KEYCHAIN_KEY_ALIAS:
1466                             if (SdkLevel.isAtLeastS()) {
1467                                 enterpriseConfig.setClientKeyPairAlias((String) value);
1468                             }
1469                             break;
1470                         case XML_TAG_DECORATED_IDENTITY_PREFIX:
1471                             if (SdkLevel.isAtLeastS()) {
1472                                 enterpriseConfig.setDecoratedIdentityPrefix((String) value);
1473                             }
1474                             break;
1475                         default:
1476                             Log.w(TAG, "Ignoring unknown value name found: " + valueName[0]);
1477                             break;
1478                     }
1479                 } else {
1480                     String tagName = in.getName();
1481                     if (tagName == null) {
1482                         throw new XmlPullParserException("Unexpected null tag found");
1483                     }
1484                     switch (tagName) {
1485                         case XML_TAG_PASSWORD:
1486                             if (!shouldExpectEncryptedCredentials || encryptionUtil == null) {
1487                                 throw new XmlPullParserException(
1488                                         "encrypted password section not expected");
1489                             }
1490                             EncryptedData encryptedData =
1491                                     EncryptedDataXmlUtil.parseFromXml(in, outerTagDepth + 1);
1492                             byte[] passwordBytes = encryptionUtil.decrypt(encryptedData);
1493                             if (passwordBytes == null) {
1494                                 Log.wtf(TAG, "Decryption of password failed");
1495                             } else {
1496                                 enterpriseConfig.setFieldValue(
1497                                         WifiEnterpriseConfig.PASSWORD_KEY,
1498                                         new String(passwordBytes));
1499                             }
1500                             break;
1501                         default:
1502                             Log.w(TAG, "Ignoring unknown tag name found: " + tagName);
1503                             break;
1504                     }
1505                 }
1506             }
1507             return enterpriseConfig;
1508         }
1509     }
1510 
1511     /**
1512      * Utility class to serialize and deseriaize {@link EncryptedData} object to XML &
1513      * vice versa. This is used by {@link com.android.server.wifi.WifiConfigStore} module.
1514      */
1515     public static class EncryptedDataXmlUtil {
1516         /**
1517          * List of XML tags corresponding to EncryptedData object elements.
1518          */
1519         private static final String XML_TAG_ENCRYPTED_DATA = "EncryptedData";
1520         private static final String XML_TAG_IV = "IV";
1521 
1522         /**
1523          * Write the NetworkSelectionStatus data elements from the provided status to the XML
1524          * stream.
1525          *
1526          * @param out           XmlSerializer instance pointing to the XML stream.
1527          * @param encryptedData EncryptedData object to be serialized.
1528          */
writeToXml(XmlSerializer out, EncryptedData encryptedData)1529         public static void writeToXml(XmlSerializer out, EncryptedData encryptedData)
1530                 throws XmlPullParserException, IOException {
1531             XmlUtil.writeNextValue(
1532                     out, XML_TAG_ENCRYPTED_DATA, encryptedData.getEncryptedData());
1533             XmlUtil.writeNextValue(out, XML_TAG_IV, encryptedData.getIv());
1534         }
1535 
1536         /**
1537          * Parses the EncryptedData data elements from the provided XML stream to a
1538          * EncryptedData object.
1539          *
1540          * @param in            XmlPullParser instance pointing to the XML stream.
1541          * @param outerTagDepth depth of the outer tag in the XML document.
1542          * @return EncryptedData object if parsing is successful, null otherwise.
1543          */
parseFromXml(XmlPullParser in, int outerTagDepth)1544         public static EncryptedData parseFromXml(XmlPullParser in, int outerTagDepth)
1545                 throws XmlPullParserException, IOException {
1546             byte[] encryptedData = null;
1547             byte[] iv = null;
1548 
1549             // Loop through and parse out all the elements from the stream within this section.
1550             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1551                 String[] valueName = new String[1];
1552                 Object value = XmlUtil.readCurrentValue(in, valueName);
1553                 if (valueName[0] == null) {
1554                     throw new XmlPullParserException("Missing value name");
1555                 }
1556                 switch (valueName[0]) {
1557                     case XML_TAG_ENCRYPTED_DATA:
1558                         encryptedData = (byte[]) value;
1559                         break;
1560                     case XML_TAG_IV:
1561                         iv = (byte[]) value;
1562                         break;
1563                     default:
1564                         Log.e(TAG, "Unknown value name found: " + valueName[0]);
1565                         break;
1566                 }
1567             }
1568             return new EncryptedData(encryptedData, iv);
1569         }
1570     }
1571 
nextElementWithin(XmlPullParser parser, int outerDepth)1572     public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)
1573             throws IOException, XmlPullParserException {
1574         return XmlUtilHelper.nextElementWithin(parser, outerDepth);
1575     }
1576 
1577     /**
1578      * Utility class to serialize and deseriaize {@link SoftApConfiguration} object to XML
1579      * & vice versa. This is used by both {@link com.android.server.wifi.SoftApStore}  modules.
1580      */
1581     public static class SoftApConfigurationXmlUtil {
1582         /**
1583          * List of XML tags corresponding to SoftApConfiguration object elements.
1584          */
1585         public static final String XML_TAG_CLIENT_MACADDRESS = "ClientMacAddress";
1586         public static final String XML_TAG_BAND_CHANNEL = "BandChannel";
1587         private static final String XML_TAG_BAND = "Band";
1588         private static final String XML_TAG_CHANNEL = "Channel";
1589 
1590         /**
1591          * Parses the client list from the provided XML stream to a ArrayList object.
1592          *
1593          * @param in            XmlPullParser instance pointing to the XML stream.
1594          * @param outerTagDepth depth of the outer tag in the XML document.
1595          * @return ArrayList object if parsing is successful, null otherwise.
1596          */
parseClientListFromXml(XmlPullParser in, int outerTagDepth)1597         public static List<MacAddress> parseClientListFromXml(XmlPullParser in,
1598                 int outerTagDepth) throws XmlPullParserException, IOException,
1599                 IllegalArgumentException {
1600             List<MacAddress> clientList = new ArrayList<>();
1601             // Loop through and parse out all the elements from the stream within this section.
1602             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1603                 String[] valueName = new String[1];
1604                 Object value = XmlUtil.readCurrentValue(in, valueName);
1605                 if (valueName[0] == null) {
1606                     throw new XmlPullParserException("Missing value name");
1607                 }
1608                 switch (valueName[0]) {
1609                     case XML_TAG_CLIENT_MACADDRESS:
1610                         MacAddress client = MacAddress.fromString((String) value);
1611                         clientList.add(client);
1612                         break;
1613                     default:
1614                         Log.e(TAG, "Unknown value name found: " + valueName[0]);
1615                         break;
1616                 }
1617             }
1618             return clientList;
1619         }
1620 
1621         /**
1622          * Write the SoftApConfiguration client control list data elements
1623          * from the provided list to the XML stream.
1624          *
1625          * @param out           XmlSerializer instance pointing to the XML stream.
1626          * @param clientList Client list object to be serialized.
1627          */
writeClientListToXml(XmlSerializer out, List<MacAddress> clientList)1628         public static void writeClientListToXml(XmlSerializer out, List<MacAddress> clientList)
1629                 throws XmlPullParserException, IOException {
1630             for (MacAddress mac: clientList) {
1631                 XmlUtil.writeNextValue(out, XML_TAG_CLIENT_MACADDRESS, mac.toString());
1632             }
1633         }
1634 
1635 
1636         /**
1637          * Parses the band and channel from the provided XML stream to a SparseIntArray object.
1638          *
1639          * @param in            XmlPullParser instance pointing to the XML stream.
1640          * @param outerTagDepth depth of the outer tag in the XML document.
1641          * @return SparseIntArray object if parsing is successful, null otherwise.
1642          */
parseChannelsFromXml(XmlPullParser in, int outerTagDepth)1643         public static SparseIntArray parseChannelsFromXml(XmlPullParser in,
1644                 int outerTagDepth) throws XmlPullParserException, IOException,
1645                 IllegalArgumentException {
1646             SparseIntArray channels = new SparseIntArray();
1647             while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
1648                 int band = ApConfigUtil.INVALID_VALUE_FOR_BAND_OR_CHANNEL;
1649                 int channel = ApConfigUtil.INVALID_VALUE_FOR_BAND_OR_CHANNEL;
1650                 switch (in.getName()) {
1651                     case XML_TAG_BAND_CHANNEL:
1652                         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth + 1)) {
1653                             String[] valueName = new String[1];
1654                             Object value = XmlUtil.readCurrentValue(in, valueName);
1655                             if (valueName[0] == null) {
1656                                 throw new XmlPullParserException("Missing value name");
1657                             }
1658                             switch (valueName[0]) {
1659                                 case XML_TAG_BAND:
1660                                     band = (int) value;
1661                                     break;
1662                                 case XML_TAG_CHANNEL:
1663                                     channel = (int) value;
1664                                     break;
1665                                 default:
1666                                     Log.e(TAG, "Unknown value name found: " + valueName[0]);
1667                                     break;
1668                             }
1669                         }
1670                         channels.put(band, channel);
1671                         break;
1672                 }
1673             }
1674             return channels;
1675         }
1676 
1677         /**
1678          * Write the SoftApConfiguration channels data elements
1679          * from the provided SparseIntArray to the XML stream.
1680          *
1681          * @param out       XmlSerializer instance pointing to the XML stream.
1682          * @param channels  SparseIntArray, which includes bands and channels, to be serialized.
1683          */
writeChannelsToXml(XmlSerializer out, SparseIntArray channels)1684         public static void writeChannelsToXml(XmlSerializer out, SparseIntArray channels)
1685                 throws XmlPullParserException, IOException {
1686             for (int i = 0; i < channels.size(); i++) {
1687                 XmlUtil.writeNextSectionStart(out, XML_TAG_BAND_CHANNEL);
1688                 XmlUtil.writeNextValue(out, XML_TAG_BAND, channels.keyAt(i));
1689                 XmlUtil.writeNextValue(out, XML_TAG_CHANNEL, channels.valueAt(i));
1690                 XmlUtil.writeNextSectionEnd(out, XML_TAG_BAND_CHANNEL);
1691             }
1692         }
1693     }
1694 }
1695 
1696