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