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