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