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